void InlinePainter::paint(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (RuntimeEnabledFeatures::slimmingPaintOffsetCachingEnabled() && !paintInfo.context->paintController().skippingCache()) { if (m_layoutInline.paintOffsetChanged(paintOffset)) { paintInfo.context->paintController().invalidatePaintOffset(m_layoutInline); LineBoxListPainter(*m_layoutInline.lineBoxes()).invalidateLineBoxPaintOffsets(paintInfo); } // Set previousPaintOffset here in case that m_layoutInline paints nothing and no // LayoutObjectDrawingRecorder updates its previousPaintOffset. // TODO(wangxianzhu): Integrate paint offset checking into new paint invalidation. m_layoutInline.mutableForPainting().setPreviousPaintOffset(paintOffset); } // FIXME: When Skia supports annotation rect covering (https://code.google.com/p/skia/issues/detail?id=3872), // this rect may be covered by foreground and descendant drawings. Then we may need a dedicated paint phase. if (paintInfo.phase == PaintPhaseForeground && paintInfo.isPrinting()) ObjectPainter(m_layoutInline).addPDFURLRectIfNeeded(paintInfo, paintOffset); if (paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline || paintInfo.phase == PaintPhaseChildOutlines) { ObjectPainter painter(m_layoutInline); if (paintInfo.phase != PaintPhaseSelfOutline) painter.paintInlineChildrenOutlines(paintInfo, paintOffset); if (paintInfo.phase != PaintPhaseChildOutlines && !m_layoutInline.isElementContinuation()) painter.paintOutline(paintInfo, paintOffset); return; } LineBoxListPainter(*m_layoutInline.lineBoxes()).paint(m_layoutInline, paintInfo, paintOffset); }
void SVGRootInlineBoxPainter::paint(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection); bool hasSelection = !paintInfo.isPrinting() && m_svgRootInlineBox.selectionState() != SelectionNone; PaintInfo paintInfoBeforeFiltering(paintInfo); if (hasSelection && !LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*paintInfoBeforeFiltering.context, m_svgRootInlineBox.layoutObject(), paintInfoBeforeFiltering.phase, paintOffset)) { LayoutObjectDrawingRecorder recorder(*paintInfoBeforeFiltering.context, m_svgRootInlineBox.layoutObject(), paintInfoBeforeFiltering.phase, paintInfoBeforeFiltering.cullRect().m_rect, paintOffset); for (InlineBox* child = m_svgRootInlineBox.firstChild(); child; child = child->nextOnLine()) { if (child->isSVGInlineTextBox()) SVGInlineTextBoxPainter(*toSVGInlineTextBox(child)).paintSelectionBackground(paintInfoBeforeFiltering); else if (child->isSVGInlineFlowBox()) SVGInlineFlowBoxPainter(*toSVGInlineFlowBox(child)).paintSelectionBackground(paintInfoBeforeFiltering); } } SVGPaintContext paintContext(m_svgRootInlineBox.layoutObject(), paintInfoBeforeFiltering); if (paintContext.applyClipMaskAndFilterIfNecessary()) { for (InlineBox* child = m_svgRootInlineBox.firstChild(); child; child = child->nextOnLine()) child->paint(paintContext.paintInfo(), paintOffset, 0, 0); } }
void LineBoxListPainter::paint(LayoutBoxModelObject* layoutObject, const PaintInfo& paintInfo, const LayoutPoint& paintOffset) const { ASSERT(paintInfo.phase != PaintPhaseOutline && paintInfo.phase != PaintPhaseSelfOutline && paintInfo.phase != PaintPhaseChildOutlines); // Only paint during the foreground/selection phases. if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection && paintInfo.phase != PaintPhaseTextClip && paintInfo.phase != PaintPhaseMask) return; ASSERT(layoutObject->isLayoutBlock() || (layoutObject->isLayoutInline() && layoutObject->hasLayer())); // The only way an inline could paint like this is if it has a layer. // FIXME: When Skia supports annotation rect covering (https://code.google.com/p/skia/issues/detail?id=3872), // these rects may be covered line box drawings. Then we may need a dedicated paint phase. if (paintInfo.phase == PaintPhaseForeground && paintInfo.isPrinting()) addPDFURLRectsForInlineChildrenRecursively(layoutObject, paintInfo, paintOffset); // If we have no lines then we have no work to do. if (!m_lineBoxList.firstLineBox()) return; if (!m_lineBoxList.anyLineIntersectsRect(LineLayoutBoxModel(layoutObject), LayoutRect(paintInfo.rect), paintOffset)) return; PaintInfo info(paintInfo); // See if our root lines intersect with the dirty rect. If so, then we paint // them. Note that boxes can easily overlap, so we can't make any assumptions // based off positions of our first line box or our last line box. for (InlineFlowBox* curr = m_lineBoxList.firstLineBox(); curr; curr = curr->nextLineBox()) { if (m_lineBoxList.lineIntersectsDirtyRect(LineLayoutBoxModel(layoutObject), curr, info, paintOffset)) { RootInlineBox& root = curr->root(); curr->paint(info, paintOffset, root.lineTop(), root.lineBottom()); } } }
bool BlockPainter::intersectsPaintRect( const PaintInfo& paintInfo, const LayoutPoint& adjustedPaintOffset) const { LayoutRect overflowRect; if (paintInfo.isPrinting() && m_layoutBlock.isAnonymousBlock() && m_layoutBlock.childrenInline()) { // For case <a href="..."><div>...</div></a>, when m_layoutBlock is the // anonymous container of <a>, the anonymous container's visual overflow is // empty, but we need to continue painting to output <a>'s PDF URL rect // which covers the continuations, as if we included <a>'s PDF URL rect into // m_layoutBlock's visual overflow. Vector<LayoutRect> rects; m_layoutBlock.addElementVisualOverflowRects(rects, LayoutPoint()); overflowRect = unionRect(rects); } overflowRect.unite(m_layoutBlock.visualOverflowRect()); bool usesCompositedScrolling = m_layoutBlock.hasOverflowModel() && m_layoutBlock.usesCompositedScrolling(); if (usesCompositedScrolling) { LayoutRect layoutOverflowRect = m_layoutBlock.layoutOverflowRect(); overflowRect.unite(layoutOverflowRect); } m_layoutBlock.flipForWritingMode(overflowRect); // Scrolling is applied in physical space, which is why it is after the flip // above. if (usesCompositedScrolling) { overflowRect.move(-m_layoutBlock.scrolledContentOffset()); } overflowRect.moveBy(adjustedPaintOffset); return paintInfo.cullRect().intersectsCullRect(overflowRect); }
void LineBoxListPainter::paint(const LayoutBoxModelObject& layoutObject, const PaintInfo& paintInfo, const LayoutPoint& paintOffset) const { ASSERT(!shouldPaintSelfOutline(paintInfo.phase) && !shouldPaintDescendantOutlines(paintInfo.phase)); // Only paint during the foreground/selection phases. if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection && paintInfo.phase != PaintPhaseTextClip && paintInfo.phase != PaintPhaseMask) return; ASSERT(layoutObject.isLayoutBlock() || (layoutObject.isLayoutInline() && layoutObject.hasLayer())); // The only way an inline could paint like this is if it has a layer. if (paintInfo.phase == PaintPhaseForeground && paintInfo.isPrinting()) addPDFURLRectsForInlineChildrenRecursively(layoutObject, paintInfo, paintOffset); // If we have no lines then we have no work to do. if (!m_lineBoxList.firstLineBox()) return; if (!m_lineBoxList.anyLineIntersectsRect(LineLayoutBoxModel(const_cast<LayoutBoxModelObject*>(&layoutObject)), paintInfo.cullRect(), paintOffset)) return; PaintInfo info(paintInfo); // See if our root lines intersect with the dirty rect. If so, then we paint // them. Note that boxes can easily overlap, so we can't make any assumptions // based off positions of our first line box or our last line box. for (InlineFlowBox* curr = m_lineBoxList.firstLineBox(); curr; curr = curr->nextLineBox()) { if (m_lineBoxList.lineIntersectsDirtyRect(LineLayoutBoxModel(const_cast<LayoutBoxModelObject*>(&layoutObject)), curr, info.cullRect(), paintOffset)) { RootInlineBox& root = curr->root(); curr->paint(info, paintOffset, root.lineTop(), root.lineBottom()); } } }
void InlinePainter::paint(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { // FIXME: When Skia supports annotation rect covering (https://code.google.com/p/skia/issues/detail?id=3872), // this rect may be covered by foreground and descendant drawings. Then we may need a dedicated paint phase. if (paintInfo.phase == PaintPhaseForeground && paintInfo.isPrinting()) ObjectPainter(m_layoutInline).addPDFURLRectIfNeeded(paintInfo, paintOffset); LineBoxListPainter(*m_layoutInline.lineBoxes()).paint(&m_layoutInline, paintInfo, paintOffset); }
void ImagePainter::paintAreaElementFocusRing(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { Document& document = m_layoutImage.document(); if (paintInfo.isPrinting() || !document.frame()->selection().isFocusedAndActive()) return; Element* focusedElement = document.focusedElement(); if (!isHTMLAreaElement(focusedElement)) return; HTMLAreaElement& areaElement = toHTMLAreaElement(*focusedElement); if (areaElement.imageElement() != m_layoutImage.node()) return; // Even if the theme handles focus ring drawing for entire elements, it won't // do it for an area within an image, so we don't call // LayoutTheme::themeDrawsFocusRing here. const ComputedStyle& areaElementStyle = *areaElement.ensureComputedStyle(); // If the outline width is 0 we want to avoid drawing anything even if we // don't use the value directly. if (!areaElementStyle.outlineWidth()) return; Path path = areaElement.getPath(&m_layoutImage); if (path.isEmpty()) return; LayoutPoint adjustedPaintOffset = paintOffset; adjustedPaintOffset.moveBy(m_layoutImage.location()); path.translate(FloatSize(adjustedPaintOffset.x(), adjustedPaintOffset.y())); if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible( paintInfo.context, m_layoutImage, DisplayItem::kImageAreaFocusRing)) return; LayoutRect focusRect = m_layoutImage.contentBoxRect(); focusRect.moveBy(adjustedPaintOffset); LayoutObjectDrawingRecorder drawingRecorder(paintInfo.context, m_layoutImage, DisplayItem::kImageAreaFocusRing, focusRect); // FIXME: Clip path instead of context when Skia pathops is ready. // https://crbug.com/251206 paintInfo.context.save(); paintInfo.context.clip(pixelSnappedIntRect(focusRect)); paintInfo.context.drawFocusRing( path, areaElementStyle.getOutlineStrokeWidthForFocusRing(), areaElementStyle.outlineOffset(), m_layoutImage.resolveColor(areaElementStyle, CSSPropertyOutlineColor)); paintInfo.context.restore(); }
void PartPainter::paint(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (!m_layoutPart.shouldPaint(paintInfo, paintOffset)) return; LayoutPoint adjustedPaintOffset = paintOffset + m_layoutPart.location(); LayoutRect borderRect(adjustedPaintOffset, m_layoutPart.size()); if (m_layoutPart.hasBoxDecorationBackground() && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection)) BoxPainter(m_layoutPart).paintBoxDecorationBackground(paintInfo, adjustedPaintOffset); if (paintInfo.phase == PaintPhaseMask) { BoxPainter(m_layoutPart).paintMask(paintInfo, adjustedPaintOffset); return; } if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && m_layoutPart.style()->hasOutline()) ObjectPainter(m_layoutPart).paintOutline(paintInfo, adjustedPaintOffset); if (paintInfo.phase != PaintPhaseForeground) return; { Optional<RoundedInnerRectClipper> clipper; if (m_layoutPart.style()->hasBorderRadius()) { if (borderRect.isEmpty()) return; FloatRoundedRect roundedInnerRect = m_layoutPart.style()->getRoundedInnerBorderFor(borderRect, LayoutRectOutsets( -(m_layoutPart.paddingTop() + m_layoutPart.borderTop()), -(m_layoutPart.paddingRight() + m_layoutPart.borderRight()), -(m_layoutPart.paddingBottom() + m_layoutPart.borderBottom()), -(m_layoutPart.paddingLeft() + m_layoutPart.borderLeft())), true, true); clipper.emplace(m_layoutPart, paintInfo, borderRect, roundedInnerRect, ApplyToDisplayList); } if (m_layoutPart.widget()) m_layoutPart.paintContents(paintInfo, paintOffset); } // Paint a partially transparent wash over selected widgets. if (isSelected() && !paintInfo.isPrinting() && !LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*paintInfo.context, m_layoutPart, paintInfo.phase, adjustedPaintOffset)) { LayoutRect rect = m_layoutPart.localSelectionRect(); rect.moveBy(adjustedPaintOffset); IntRect selectionRect = pixelSnappedIntRect(rect); LayoutObjectDrawingRecorder drawingRecorder(*paintInfo.context, m_layoutPart, paintInfo.phase, selectionRect, adjustedPaintOffset); paintInfo.context->fillRect(selectionRect, m_layoutPart.selectionBackgroundColor()); } if (m_layoutPart.canResize()) ScrollableAreaPainter(*m_layoutPart.layer()->scrollableArea()).paintResizer(paintInfo.context, roundedIntPoint(adjustedPaintOffset), paintInfo.cullRect()); }
// static TextPainter::Style TextPainter::textPaintingStyle(LineLayoutItem lineLayoutItem, const ComputedStyle& style, const PaintInfo& paintInfo) { TextPainter::Style textStyle; bool isPrinting = paintInfo.isPrinting(); if (paintInfo.phase == PaintPhaseTextClip) { // When we use the text as a clip, we only care about the alpha, thus we // make all the colors black. textStyle.currentColor = Color::black; textStyle.fillColor = Color::black; textStyle.strokeColor = Color::black; textStyle.emphasisMarkColor = Color::black; textStyle.strokeWidth = style.textStrokeWidth(); textStyle.shadow = 0; } else { textStyle.currentColor = style.visitedDependentColor(CSSPropertyColor); textStyle.fillColor = lineLayoutItem.resolveColor(style, CSSPropertyWebkitTextFillColor); textStyle.strokeColor = lineLayoutItem.resolveColor(style, CSSPropertyWebkitTextStrokeColor); textStyle.emphasisMarkColor = lineLayoutItem.resolveColor(style, CSSPropertyWebkitTextEmphasisColor); textStyle.strokeWidth = style.textStrokeWidth(); textStyle.shadow = style.textShadow(); // Adjust text color when printing with a white background. ASSERT(lineLayoutItem.document().printing() == isPrinting); bool forceBackgroundToWhite = BoxPainter::shouldForceWhiteBackgroundForPrintEconomy( style, lineLayoutItem.document()); if (forceBackgroundToWhite) { textStyle.fillColor = textColorForWhiteBackground(textStyle.fillColor); textStyle.strokeColor = textColorForWhiteBackground(textStyle.strokeColor); textStyle.emphasisMarkColor = textColorForWhiteBackground(textStyle.emphasisMarkColor); } // Text shadows are disabled when printing. http://crbug.com/258321 if (isPrinting) textStyle.shadow = 0; } return textStyle; }
void ImagePainter::paintAreaElementFocusRing(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { // TODO(wangxianzhu): In other places, we just paint focus ring if outline style is auto. // We should also do that here to keep consistency. Document& document = m_layoutImage.document(); if (paintInfo.isPrinting() || !document.frame()->selection().isFocusedAndActive()) return; Element* focusedElement = document.focusedElement(); if (!isHTMLAreaElement(focusedElement)) return; HTMLAreaElement& areaElement = toHTMLAreaElement(*focusedElement); if (areaElement.imageElement() != m_layoutImage.node()) return; // Even if the theme handles focus ring drawing for entire elements, it won't do it for // an area within an image, so we don't call LayoutTheme::themeDrawsFocusRing here. Path path = areaElement.computePath(&m_layoutImage); if (path.isEmpty()) return; const ComputedStyle& areaElementStyle = *areaElement.ensureComputedStyle(); int outlineWidth = areaElementStyle.outlineWidth(); if (!outlineWidth) return; if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*paintInfo.context, m_layoutImage, paintInfo.phase, paintOffset)) return; IntRect focusRect = m_layoutImage.absoluteContentBox(); LayoutObjectDrawingRecorder drawingRecorder(*paintInfo.context, m_layoutImage, paintInfo.phase, focusRect, paintOffset); // FIXME: Clip path instead of context when Skia pathops is ready. // https://crbug.com/251206 paintInfo.context->save(); paintInfo.context->clip(focusRect); paintInfo.context->drawFocusRing(path, outlineWidth, areaElementStyle.outlineOffset(), m_layoutImage.resolveColor(areaElementStyle, CSSPropertyOutlineColor)); paintInfo.context->restore(); }
void InlinePainter::paint(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { // FIXME: When Skia supports annotation rect covering (https://code.google.com/p/skia/issues/detail?id=3872), // this rect may be covered by foreground and descendant drawings. Then we may need a dedicated paint phase. if (paintInfo.phase == PaintPhaseForeground && paintInfo.isPrinting()) ObjectPainter(m_layoutInline).addPDFURLRectIfNeeded(paintInfo, paintOffset); if (paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline || paintInfo.phase == PaintPhaseChildOutlines) { ObjectPainter painter(m_layoutInline); if (paintInfo.phase != PaintPhaseSelfOutline) painter.paintInlineChildrenOutlines(paintInfo, paintOffset); if (paintInfo.phase != PaintPhaseChildOutlines && !m_layoutInline.isElementContinuation()) painter.paintOutline(paintInfo, paintOffset); return; } LineBoxListPainter(*m_layoutInline.lineBoxes()).paint(&m_layoutInline, paintInfo, paintOffset); }
void EllipsisBoxPainter::paintEllipsis(const PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit lineTop, LayoutUnit lineBottom, const ComputedStyle& style) { bool haveSelection = !paintInfo.isPrinting() && paintInfo.phase != PaintPhaseTextClip && m_ellipsisBox.getSelectionState() != SelectionNone; LayoutRect paintRect(m_ellipsisBox.logicalFrameRect()); if (haveSelection) paintRect.unite(LayoutRect(m_ellipsisBox.selectionRect())); m_ellipsisBox.logicalRectToPhysicalRect(paintRect); paintRect.moveBy(paintOffset); GraphicsContext& context = paintInfo.context; DisplayItem::Type displayItemType = DisplayItem::paintPhaseToDrawingType(paintInfo.phase); if (DrawingRecorder::useCachedDrawingIfPossible(context, m_ellipsisBox, displayItemType)) return; DrawingRecorder recorder(context, m_ellipsisBox, displayItemType, FloatRect(paintRect)); LayoutPoint boxOrigin = m_ellipsisBox.locationIncludingFlipping(); boxOrigin.moveBy(paintOffset); LayoutRect boxRect(boxOrigin, LayoutSize(m_ellipsisBox.logicalWidth(), m_ellipsisBox.virtualLogicalHeight())); GraphicsContextStateSaver stateSaver(context); if (!m_ellipsisBox.isHorizontal()) context.concatCTM(TextPainter::rotation(boxRect, TextPainter::Clockwise)); const Font& font = style.font(); if (haveSelection) paintSelection(context, boxOrigin, style, font); else if (paintInfo.phase == PaintPhaseSelection) return; TextPainter::Style textStyle = TextPainter::textPaintingStyle(m_ellipsisBox.getLineLayoutItem(), style, paintInfo); if (haveSelection) textStyle = TextPainter::selectionPaintingStyle(m_ellipsisBox.getLineLayoutItem(), true, paintInfo, textStyle); TextRun textRun = constructTextRun(font, m_ellipsisBox.ellipsisStr(), style, TextRun::AllowTrailingExpansion); LayoutPoint textOrigin(boxOrigin.x(), boxOrigin.y() + font.getFontMetrics().ascent()); TextPainter textPainter(context, font, textRun, textOrigin, boxRect, m_ellipsisBox.isHorizontal()); textPainter.paint(0, m_ellipsisBox.ellipsisStr().length(), m_ellipsisBox.ellipsisStr().length(), textStyle); }
TextPainter::Style TextPainter::selectionPaintingStyle( LineLayoutItem lineLayoutItem, bool haveSelection, const PaintInfo& paintInfo, const TextPainter::Style& textStyle) { const LayoutObject& layoutObject = *LineLayoutAPIShim::constLayoutObjectFrom(lineLayoutItem); TextPainter::Style selectionStyle = textStyle; bool usesTextAsClip = paintInfo.phase == PaintPhaseTextClip; bool isPrinting = paintInfo.isPrinting(); if (haveSelection) { if (!usesTextAsClip) { selectionStyle.fillColor = layoutObject.selectionForegroundColor( paintInfo.getGlobalPaintFlags()); selectionStyle.emphasisMarkColor = layoutObject.selectionEmphasisMarkColor( paintInfo.getGlobalPaintFlags()); } if (const ComputedStyle* pseudoStyle = layoutObject.getCachedPseudoStyle(PseudoIdSelection)) { selectionStyle.strokeColor = usesTextAsClip ? Color::black : layoutObject.resolveColor( *pseudoStyle, CSSPropertyWebkitTextStrokeColor); selectionStyle.strokeWidth = pseudoStyle->textStrokeWidth(); selectionStyle.shadow = usesTextAsClip ? 0 : pseudoStyle->textShadow(); } // Text shadows are disabled when printing. http://crbug.com/258321 if (isPrinting) selectionStyle.shadow = 0; } return selectionStyle; }
void ReplacedPainter::paint(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (!m_layoutReplaced.shouldPaint(paintInfo, paintOffset)) return; LayoutPoint adjustedPaintOffset = paintOffset + m_layoutReplaced.location(); LayoutRect borderRect(adjustedPaintOffset, m_layoutReplaced.size()); if (m_layoutReplaced.hasBoxDecorationBackground() && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection)) m_layoutReplaced.paintBoxDecorationBackground(paintInfo, adjustedPaintOffset); if (paintInfo.phase == PaintPhaseMask) { m_layoutReplaced.paintMask(paintInfo, adjustedPaintOffset); return; } if (paintInfo.phase == PaintPhaseClippingMask && (!m_layoutReplaced.hasLayer() || !m_layoutReplaced.layer()->hasCompositedClippingMask())) return; if (paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) { if (m_layoutReplaced.styleRef().outlineWidth()) ObjectPainter(m_layoutReplaced).paintOutline(paintInfo, adjustedPaintOffset); return; } if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection && !m_layoutReplaced.canHaveChildren() && paintInfo.phase != PaintPhaseClippingMask) return; if (!paintInfo.shouldPaintWithinRoot(&m_layoutReplaced)) return; if (paintInfo.phase == PaintPhaseSelection) if (m_layoutReplaced.selectionState() == SelectionNone) return; { Optional<RoundedInnerRectClipper> clipper; bool completelyClippedOut = false; if (m_layoutReplaced.style()->hasBorderRadius()) { if (borderRect.isEmpty()) { completelyClippedOut = true; } else if (shouldApplyViewportClip(m_layoutReplaced)) { // Push a clip if we have a border radius, since we want to round the foreground content that gets painted. FloatRoundedRect roundedInnerRect = m_layoutReplaced.style()->getRoundedInnerBorderFor(borderRect, LayoutRectOutsets( -(m_layoutReplaced.paddingTop() + m_layoutReplaced.borderTop()), -(m_layoutReplaced.paddingRight() + m_layoutReplaced.borderRight()), -(m_layoutReplaced.paddingBottom() + m_layoutReplaced.borderBottom()), -(m_layoutReplaced.paddingLeft() + m_layoutReplaced.borderLeft())), true, true); clipper.emplace(m_layoutReplaced, paintInfo, borderRect, roundedInnerRect, ApplyToDisplayList); } } if (!completelyClippedOut) { if (paintInfo.phase == PaintPhaseClippingMask) { BoxPainter(m_layoutReplaced).paintClippingMask(paintInfo, adjustedPaintOffset); } else { m_layoutReplaced.paintReplaced(paintInfo, adjustedPaintOffset); } } } // The selection tint never gets clipped by border-radius rounding, since we want it to run right up to the edges of // surrounding content. bool drawSelectionTint = paintInfo.phase == PaintPhaseForeground && m_layoutReplaced.selectionState() != SelectionNone && !paintInfo.isPrinting(); if (drawSelectionTint && !LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(paintInfo.context, m_layoutReplaced, DisplayItem::SelectionTint, adjustedPaintOffset)) { LayoutRect selectionPaintingRect = m_layoutReplaced.localSelectionRect(); selectionPaintingRect.moveBy(adjustedPaintOffset); IntRect selectionPaintingIntRect = pixelSnappedIntRect(selectionPaintingRect); LayoutObjectDrawingRecorder drawingRecorder(paintInfo.context, m_layoutReplaced, DisplayItem::SelectionTint, selectionPaintingIntRect, adjustedPaintOffset); paintInfo.context.fillRect(selectionPaintingIntRect, m_layoutReplaced.selectionBackgroundColor()); } }
void BlockPainter::paintObject(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (RuntimeEnabledFeatures::slimmingPaintOffsetCachingEnabled() && m_layoutBlock.childrenInline() && !paintInfo.context.paintController().skippingCache()) { if (m_layoutBlock.paintOffsetChanged(paintOffset)) { LineBoxListPainter(m_layoutBlock.lineBoxes()).invalidateLineBoxPaintOffsets(paintInfo); paintInfo.context.paintController().invalidatePaintOffset(m_layoutBlock); } // Set previousPaintOffset here in case that m_layoutBlock paints nothing and no // LayoutObjectDrawingRecorder updates its previousPaintOffset. // TODO(wangxianzhu): Integrate paint offset checking into new paint invalidation. m_layoutBlock.mutableForPainting().setPreviousPaintOffset(paintOffset); } const PaintPhase paintPhase = paintInfo.phase; if ((paintPhase == PaintPhaseSelfBlockBackground || paintPhase == PaintPhaseBlockBackground) && m_layoutBlock.style()->visibility() == VISIBLE && m_layoutBlock.hasBoxDecorationBackground()) m_layoutBlock.paintBoxDecorationBackground(paintInfo, paintOffset); if (paintPhase == PaintPhaseMask && m_layoutBlock.style()->visibility() == VISIBLE) { m_layoutBlock.paintMask(paintInfo, paintOffset); return; } if (paintPhase == PaintPhaseClippingMask && m_layoutBlock.style()->visibility() == VISIBLE) { BoxPainter(m_layoutBlock).paintClippingMask(paintInfo, paintOffset); return; } // FIXME: When Skia supports annotation rect covering (https://code.google.com/p/skia/issues/detail?id=3872), // this rect may be covered by foreground and descendant drawings. Then we may need a dedicated paint phase. if (paintPhase == PaintPhaseForeground && paintInfo.isPrinting()) ObjectPainter(m_layoutBlock).addPDFURLRectIfNeeded(paintInfo, paintOffset); { Optional<ScrollRecorder> scrollRecorder; Optional<PaintInfo> scrolledPaintInfo; if (m_layoutBlock.hasOverflowClip()) { IntSize scrollOffset = m_layoutBlock.scrolledContentOffset(); if (m_layoutBlock.layer()->scrollsOverflow() || !scrollOffset.isZero()) { scrollRecorder.emplace(paintInfo.context, m_layoutBlock, paintPhase, scrollOffset); scrolledPaintInfo.emplace(paintInfo); AffineTransform transform; transform.translate(-scrollOffset.width(), -scrollOffset.height()); scrolledPaintInfo->updateCullRect(transform); } } // We're done. We don't bother painting any children. if (paintPhase == PaintPhaseSelfBlockBackground || paintInfo.paintRootBackgroundOnly()) return; const PaintInfo& contentsPaintInfo = scrolledPaintInfo ? *scrolledPaintInfo : paintInfo; if (paintPhase != PaintPhaseSelfOutline) paintContents(contentsPaintInfo, paintOffset); if (paintPhase == PaintPhaseForeground && !paintInfo.isPrinting()) m_layoutBlock.paintSelection(contentsPaintInfo, paintOffset); // Fill in gaps in selection on lines and between blocks. if (paintPhase == PaintPhaseFloat || paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip) m_layoutBlock.paintFloats(contentsPaintInfo, paintOffset); } if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && m_layoutBlock.style()->hasOutline() && m_layoutBlock.style()->visibility() == VISIBLE) ObjectPainter(m_layoutBlock).paintOutline(paintInfo, paintOffset); // If the caret's node's layout object's containing block is this block, and the paint action is PaintPhaseForeground, // then paint the caret. if (paintPhase == PaintPhaseForeground && m_layoutBlock.hasCaret() && !LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(paintInfo.context, m_layoutBlock, DisplayItem::Caret, paintOffset)) { LayoutRect bounds = m_layoutBlock.visualOverflowRect(); bounds.moveBy(paintOffset); LayoutObjectDrawingRecorder recorder(paintInfo.context, m_layoutBlock, DisplayItem::Caret, bounds, paintOffset); paintCarets(paintInfo, paintOffset); } }
void PartPainter::paint(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { LayoutPoint adjustedPaintOffset = paintOffset + m_layoutPart.location(); if (!ReplacedPainter(m_layoutPart) .shouldPaint(paintInfo, adjustedPaintOffset)) return; LayoutRect borderRect(adjustedPaintOffset, m_layoutPart.size()); if (m_layoutPart.hasBoxDecorationBackground() && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection)) BoxPainter(m_layoutPart) .paintBoxDecorationBackground(paintInfo, adjustedPaintOffset); if (paintInfo.phase == PaintPhaseMask) { BoxPainter(m_layoutPart).paintMask(paintInfo, adjustedPaintOffset); return; } if (shouldPaintSelfOutline(paintInfo.phase)) ObjectPainter(m_layoutPart).paintOutline(paintInfo, adjustedPaintOffset); if (paintInfo.phase != PaintPhaseForeground) return; if (m_layoutPart.widget()) { // TODO(schenney) crbug.com/93805 Speculative release assert to verify that // the crashes we see in widget painting are due to a destroyed LayoutPart // object. CHECK(m_layoutPart.node()); Optional<RoundedInnerRectClipper> clipper; if (m_layoutPart.style()->hasBorderRadius()) { if (borderRect.isEmpty()) return; FloatRoundedRect roundedInnerRect = m_layoutPart.style()->getRoundedInnerBorderFor( borderRect, LayoutRectOutsets( -(m_layoutPart.paddingTop() + m_layoutPart.borderTop()), -(m_layoutPart.paddingRight() + m_layoutPart.borderRight()), -(m_layoutPart.paddingBottom() + m_layoutPart.borderBottom()), -(m_layoutPart.paddingLeft() + m_layoutPart.borderLeft())), true, true); clipper.emplace(m_layoutPart, paintInfo, borderRect, roundedInnerRect, ApplyToDisplayList); } m_layoutPart.paintContents(paintInfo, paintOffset); } // Paint a partially transparent wash over selected widgets. if (isSelected() && !paintInfo.isPrinting() && !LayoutObjectDrawingRecorder::useCachedDrawingIfPossible( paintInfo.context, m_layoutPart, paintInfo.phase)) { LayoutRect rect = m_layoutPart.localSelectionRect(); rect.moveBy(adjustedPaintOffset); IntRect selectionRect = pixelSnappedIntRect(rect); LayoutObjectDrawingRecorder drawingRecorder(paintInfo.context, m_layoutPart, paintInfo.phase, selectionRect); paintInfo.context.fillRect(selectionRect, m_layoutPart.selectionBackgroundColor()); } if (m_layoutPart.canResize()) ScrollableAreaPainter(*m_layoutPart.layer()->getScrollableArea()) .paintResizer(paintInfo.context, roundedIntPoint(adjustedPaintOffset), paintInfo.cullRect()); }
void BlockPainter::paintObject(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { const PaintPhase paintPhase = paintInfo.phase; if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && m_layoutBlock.style()->visibility() == VISIBLE && m_layoutBlock.hasBoxDecorationBackground()) m_layoutBlock.paintBoxDecorationBackground(paintInfo, paintOffset); if (paintPhase == PaintPhaseMask && m_layoutBlock.style()->visibility() == VISIBLE) { m_layoutBlock.paintMask(paintInfo, paintOffset); return; } if (paintPhase == PaintPhaseClippingMask && m_layoutBlock.style()->visibility() == VISIBLE) { BoxPainter(m_layoutBlock).paintClippingMask(paintInfo, paintOffset); return; } // FIXME: When Skia supports annotation rect covering (https://code.google.com/p/skia/issues/detail?id=3872), // this rect may be covered by foreground and descendant drawings. Then we may need a dedicated paint phase. if (paintPhase == PaintPhaseForeground && paintInfo.isPrinting()) ObjectPainter(m_layoutBlock).addPDFURLRectIfNeeded(paintInfo, paintOffset); { Optional<ScrollRecorder> scrollRecorder; Optional<PaintInfo> scrolledPaintInfo; if (m_layoutBlock.hasOverflowClip()) { IntSize scrollOffset = m_layoutBlock.scrolledContentOffset(); if (m_layoutBlock.layer()->scrollsOverflow() || !scrollOffset.isZero()) { scrollRecorder.emplace(*paintInfo.context, m_layoutBlock, paintPhase, scrollOffset); scrolledPaintInfo.emplace(paintInfo); scrolledPaintInfo->rect.move(scrollOffset); } } // We're done. We don't bother painting any children. if (paintPhase == PaintPhaseBlockBackground || paintInfo.paintRootBackgroundOnly()) return; const PaintInfo& contentsPaintInfo = scrolledPaintInfo ? *scrolledPaintInfo : paintInfo; if (paintPhase != PaintPhaseSelfOutline) paintContents(contentsPaintInfo, paintOffset); if (paintPhase == PaintPhaseForeground && !paintInfo.isPrinting()) m_layoutBlock.paintSelection(contentsPaintInfo, paintOffset); // Fill in gaps in selection on lines and between blocks. if (paintPhase == PaintPhaseFloat || paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip) m_layoutBlock.paintFloats(contentsPaintInfo, paintOffset, paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip); } if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && m_layoutBlock.style()->hasOutline() && m_layoutBlock.style()->visibility() == VISIBLE) { // Don't paint focus ring for anonymous block continuation because the // inline element having outline-style:auto paints the whole focus ring. if (!m_layoutBlock.style()->outlineStyleIsAuto() || !m_layoutBlock.isAnonymousBlockContinuation()) ObjectPainter(m_layoutBlock).paintOutline(paintInfo, LayoutRect(paintOffset, m_layoutBlock.size()), visualOverflowRectWithPaintOffset(m_layoutBlock, paintOffset)); } if (paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseChildOutlines) paintContinuationOutlines(paintInfo, paintOffset); // If the caret's node's layout object's containing block is this block, and the paint action is PaintPhaseForeground, // then paint the caret. if (paintPhase == PaintPhaseForeground && hasCaret() && !LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*paintInfo.context, m_layoutBlock, DisplayItem::Caret)) { LayoutObjectDrawingRecorder recorder(*paintInfo.context, m_layoutBlock, DisplayItem::Caret, visualOverflowRectWithPaintOffset(m_layoutBlock, paintOffset)); paintCarets(paintInfo, paintOffset); } }
void BlockPainter::paintObject(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { const PaintPhase paintPhase = paintInfo.phase; if (shouldPaintSelfBlockBackground(paintPhase)) { if (m_layoutBlock.style()->visibility() == EVisibility::Visible && m_layoutBlock.hasBoxDecorationBackground()) m_layoutBlock.paintBoxDecorationBackground(paintInfo, paintOffset); // We're done. We don't bother painting any children. if (paintPhase == PaintPhaseSelfBlockBackgroundOnly) return; } if (paintInfo.paintRootBackgroundOnly()) return; if (paintPhase == PaintPhaseMask && m_layoutBlock.style()->visibility() == EVisibility::Visible) { m_layoutBlock.paintMask(paintInfo, paintOffset); return; } if (paintPhase == PaintPhaseClippingMask && m_layoutBlock.style()->visibility() == EVisibility::Visible) { BoxPainter(m_layoutBlock).paintClippingMask(paintInfo, paintOffset); return; } if (paintPhase == PaintPhaseForeground && paintInfo.isPrinting()) ObjectPainter(m_layoutBlock).addPDFURLRectIfNeeded(paintInfo, paintOffset); if (paintPhase != PaintPhaseSelfOutlineOnly) { Optional<ScopedPaintChunkProperties> m_scopedScrollProperty; Optional<ScrollRecorder> scrollRecorder; Optional<PaintInfo> scrolledPaintInfo; if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { const auto* objectProperties = m_layoutBlock.paintProperties(); if (auto* scroll = objectProperties ? objectProperties->scroll() : nullptr) { PaintChunkProperties properties(paintInfo.context.getPaintController() .currentPaintChunkProperties()); auto* scrollTranslation = objectProperties->scrollTranslation(); DCHECK(scrollTranslation); properties.transform = scrollTranslation; properties.scroll = scroll; m_scopedScrollProperty.emplace( paintInfo.context.getPaintController(), m_layoutBlock, DisplayItem::paintPhaseToDrawingType(paintPhase), properties); scrolledPaintInfo.emplace(paintInfo); scrolledPaintInfo->updateCullRect( scrollTranslation->matrix().toAffineTransform()); } } else if (m_layoutBlock.hasOverflowClip()) { IntSize scrollOffset = m_layoutBlock.scrolledContentOffset(); if (m_layoutBlock.layer()->scrollsOverflow() || !scrollOffset.isZero()) { scrollRecorder.emplace(paintInfo.context, m_layoutBlock, paintPhase, scrollOffset); scrolledPaintInfo.emplace(paintInfo); AffineTransform transform; transform.translate(-scrollOffset.width(), -scrollOffset.height()); scrolledPaintInfo->updateCullRect(transform); } } const PaintInfo& contentsPaintInfo = scrolledPaintInfo ? *scrolledPaintInfo : paintInfo; if (m_layoutBlock.isLayoutBlockFlow()) { BlockFlowPainter blockFlowPainter(toLayoutBlockFlow(m_layoutBlock)); blockFlowPainter.paintContents(contentsPaintInfo, paintOffset); if (paintPhase == PaintPhaseFloat || paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip) blockFlowPainter.paintFloats(contentsPaintInfo, paintOffset); } else { paintContents(contentsPaintInfo, paintOffset); } } if (shouldPaintSelfOutline(paintPhase)) ObjectPainter(m_layoutBlock).paintOutline(paintInfo, paintOffset); // If the caret's node's layout object's containing block is this block, and // the paint action is PaintPhaseForeground, then paint the caret. if (paintPhase == PaintPhaseForeground && m_layoutBlock.hasCaret()) paintCarets(paintInfo, paintOffset); }