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 ImagePainter::paintReplaced(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { LayoutUnit cWidth = m_layoutImage.contentWidth(); LayoutUnit cHeight = m_layoutImage.contentHeight(); GraphicsContext* context = paintInfo.context; if (!m_layoutImage.imageResource()->hasImage()) { if (paintInfo.phase == PaintPhaseSelection) return; if (cWidth > 2 && cHeight > 2) { if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*context, m_layoutImage, paintInfo.phase)) return; // Draw an outline rect where the image should be. IntRect paintRect = pixelSnappedIntRect(LayoutRect(paintOffset.x() + m_layoutImage.borderLeft() + m_layoutImage.paddingLeft(), paintOffset.y() + m_layoutImage.borderTop() + m_layoutImage.paddingTop(), cWidth, cHeight)); LayoutObjectDrawingRecorder drawingRecorder(*context, m_layoutImage, paintInfo.phase, paintRect); context->setStrokeStyle(SolidStroke); context->setStrokeColor(Color::lightGray); context->setFillColor(Color::transparent); context->drawRect(paintRect); } } else if (cWidth > 0 && cHeight > 0) { if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*context, m_layoutImage, paintInfo.phase)) return; LayoutRect contentRect = m_layoutImage.contentBoxRect(); contentRect.moveBy(paintOffset); LayoutRect paintRect = m_layoutImage.replacedContentRect(); paintRect.moveBy(paintOffset); LayoutObjectDrawingRecorder drawingRecorder(*context, m_layoutImage, paintInfo.phase, contentRect); bool clip = !contentRect.contains(paintRect); if (clip) { context->save(); context->clip(contentRect); } paintIntoRect(context, paintRect); if (clip) 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()); }
void EmbeddedObjectPainter::paintReplaced(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (!m_layoutEmbeddedObject.showsUnavailablePluginIndicator()) return; if (paintInfo.phase == PaintPhaseSelection) return; GraphicsContext& context = paintInfo.context; if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible( context, m_layoutEmbeddedObject, paintInfo.phase)) return; LayoutRect contentRect(m_layoutEmbeddedObject.contentBoxRect()); contentRect.moveBy(paintOffset); LayoutObjectDrawingRecorder drawingRecorder(context, m_layoutEmbeddedObject, paintInfo.phase, contentRect); GraphicsContextStateSaver stateSaver(context); context.clip(pixelSnappedIntRect(contentRect)); Font font = replacementTextFont(); const SimpleFontData* fontData = font.primaryFont(); DCHECK(fontData); if (!fontData) return; TextRun textRun(m_layoutEmbeddedObject.unavailablePluginReplacementText()); FloatSize textGeometry(font.width(textRun), fontData->getFontMetrics().height()); LayoutRect backgroundRect( 0, 0, textGeometry.width() + 2 * replacementTextRoundedRectLeftRightTextMargin, replacementTextRoundedRectHeight); backgroundRect.move(contentRect.center() - backgroundRect.center()); backgroundRect = LayoutRect(pixelSnappedIntRect(backgroundRect)); Path roundedBackgroundRect; FloatRect floatBackgroundRect(backgroundRect); roundedBackgroundRect.addRoundedRect( floatBackgroundRect, FloatSize(replacementTextRoundedRectRadius, replacementTextRoundedRectRadius)); context.setFillColor( scaleAlpha(Color::white, replacementTextRoundedRectOpacity)); context.fillPath(roundedBackgroundRect); FloatRect textRect(FloatPoint(), textGeometry); textRect.move(FloatPoint(contentRect.center()) - textRect.center()); TextRunPaintInfo runInfo(textRun); runInfo.bounds = floatBackgroundRect; context.setFillColor(scaleAlpha(Color::black, replacementTextTextOpacity)); context.drawBidiText( font, runInfo, textRect.location() + FloatSize(0, fontData->getFontMetrics().ascent())); }
void ImagePainter::paintReplaced(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { LayoutUnit cWidth = m_layoutImage.contentWidth(); LayoutUnit cHeight = m_layoutImage.contentHeight(); GraphicsContext* context = paintInfo.context; if (!m_layoutImage.imageResource()->hasImage()) { if (paintInfo.phase == PaintPhaseSelection) return; if (cWidth > 2 && cHeight > 2) { if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*context, m_layoutImage, paintInfo.phase, paintOffset)) return; // Draw an outline rect where the image should be. IntRect paintRect = pixelSnappedIntRect(LayoutRect(paintOffset.x() + m_layoutImage.borderLeft() + m_layoutImage.paddingLeft(), paintOffset.y() + m_layoutImage.borderTop() + m_layoutImage.paddingTop(), cWidth, cHeight)); LayoutObjectDrawingRecorder drawingRecorder(*context, m_layoutImage, paintInfo.phase, paintRect, paintOffset); context->setStrokeStyle(SolidStroke); context->setStrokeColor(Color::lightGray); context->setFillColor(Color::transparent); context->drawRect(paintRect); } } else if (cWidth > 0 && cHeight > 0) { LayoutRect contentRect = m_layoutImage.contentBoxRect(); contentRect.moveBy(paintOffset); LayoutRect paintRect = m_layoutImage.replacedContentRect(); paintRect.moveBy(paintOffset); Optional<ClipRecorder> clipRecorder; if (!contentRect.contains(paintRect)) { // TODO(fmalita): can we get rid of this clip and adjust the image src/dst rect instead? clipRecorder.emplace(*context, m_layoutImage, paintInfo.displayItemTypeForClipping(), contentRect); } if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*context, m_layoutImage, paintInfo.phase, paintOffset)) return; LayoutObjectDrawingRecorder drawingRecorder(*context, m_layoutImage, paintInfo.phase, contentRect, paintOffset); paintIntoRect(context, paintRect); } }
void FramePainter::paintScrollCorner(GraphicsContext* context, const IntRect& cornerRect) { if (m_frameView.scrollCorner()) { bool needsBackground = m_frameView.frame().isMainFrame(); if (needsBackground) { DrawingRecorder drawingRecorder(*context, *m_frameView.layoutView(), DisplayItem::ScrollbarCorner, cornerRect); if (!drawingRecorder.canUseCachedDrawing()) context->fillRect(cornerRect, m_frameView.baseBackgroundColor()); } ScrollbarPainter::paintIntoRect(m_frameView.scrollCorner(), context, cornerRect.location(), LayoutRect(cornerRect)); return; } ScrollbarTheme::theme()->paintScrollCorner(context, m_frameView, cornerRect); }
void FramePainter::paintScrollCorner(GraphicsContext& context, const IntRect& cornerRect) { if (frameView().scrollCorner()) { bool needsBackground = frameView().frame().isMainFrame(); if (needsBackground && !LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(context, *frameView().layoutView(), DisplayItem::ScrollbarCorner, LayoutPoint())) { LayoutObjectDrawingRecorder drawingRecorder(context, *frameView().layoutView(), DisplayItem::ScrollbarCorner, FloatRect(cornerRect), LayoutPoint()); context.fillRect(cornerRect, frameView().baseBackgroundColor()); } ScrollbarPainter::paintIntoRect(*frameView().scrollCorner(), context, cornerRect.location(), LayoutRect(cornerRect)); return; } ScrollbarTheme::theme().paintScrollCorner(context, *frameView().layoutView(), cornerRect); }
bool SVGClipPainter::drawClipAsMask( GraphicsContext& context, const LayoutObject& layoutObject, const FloatRect& targetBoundingBox, const FloatRect& targetPaintInvalidationRect, const AffineTransform& localTransform, const FloatPoint& layerPositionOffset) { if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible( context, layoutObject, DisplayItem::kSVGClip)) return true; SkPictureBuilder maskPictureBuilder(targetPaintInvalidationRect, nullptr, &context); GraphicsContext& maskContext = maskPictureBuilder.context(); { TransformRecorder recorder(maskContext, layoutObject, localTransform); // Apply any clip-path clipping this clipPath (nested shape/clipPath.) Optional<ClipPathClipper> nestedClipPathClipper; if (ClipPathOperation* clipPathOperation = m_clip.styleRef().clipPath()) nestedClipPathClipper.emplace(maskContext, *clipPathOperation, m_clip, targetBoundingBox, layerPositionOffset); { AffineTransform contentTransform; if (m_clip.clipPathUnits() == SVGUnitTypes::kSvgUnitTypeObjectboundingbox) { contentTransform.translate(targetBoundingBox.x(), targetBoundingBox.y()); contentTransform.scaleNonUniform(targetBoundingBox.width(), targetBoundingBox.height()); } SubtreeContentTransformScope contentTransformScope(contentTransform); TransformRecorder contentTransformRecorder(maskContext, layoutObject, contentTransform); maskContext.getPaintController().createAndAppend<DrawingDisplayItem>( layoutObject, DisplayItem::kSVGClip, m_clip.createContentPicture()); } } LayoutObjectDrawingRecorder drawingRecorder(context, layoutObject, DisplayItem::kSVGClip, targetPaintInvalidationRect); sk_sp<SkPicture> maskPicture = maskPictureBuilder.endRecording(); context.drawPicture(maskPicture.get()); return true; }
void SVGClipPainter::drawClipMaskContent(GraphicsContext* context, const LayoutObject& layoutObject, const FloatRect& targetBoundingBox, const FloatRect& targetPaintInvalidationRect) { ASSERT(context); AffineTransform contentTransformation; RefPtr<const SkPicture> clipContentPicture = m_clip.createContentPicture(contentTransformation, targetBoundingBox, context); if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*context, layoutObject, DisplayItem::SVGClip, LayoutPoint())) return; LayoutObjectDrawingRecorder drawingRecorder(*context, layoutObject, DisplayItem::SVGClip, targetPaintInvalidationRect, LayoutPoint()); context->save(); context->concatCTM(contentTransformation); context->drawPicture(clipContentPicture.get()); context->restore(); }
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 CaretBase::paintCaret(Node* node, GraphicsContext& context, const LayoutPoint& paintOffset, DisplayItem::Type displayItemType) const { if (DrawingRecorder::useCachedDrawingIfPossible(context, *this, displayItemType)) return; LayoutRect drawingRect = localCaretRectWithoutUpdate(); if (LayoutBlock* layoutObject = caretLayoutObject(node)) layoutObject->flipForWritingMode(drawingRect); drawingRect.moveBy(paintOffset); const Color caretColor = node->layoutObject()->resolveColor(CSSPropertyColor); IntRect paintRect = pixelSnappedIntRect(drawingRect); DrawingRecorder drawingRecorder(context, *this, DisplayItem::kCaret, paintRect); context.fillRect(paintRect, caretColor); }
void ImagePainter::paintAreaElementFocusRing(const PaintInfo& paintInfo) { Document& document = m_layoutImage.document(); if (document.printing() || !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::supportsFocusRing here. Path path = areaElement.computePath(&m_layoutImage); if (path.isEmpty()) return; const ComputedStyle& areaElementStyle = *areaElement.ensureComputedStyle(); unsigned short outlineWidth = areaElementStyle.outlineWidth(); if (!outlineWidth) return; IntRect focusRect = m_layoutImage.absoluteContentBox(); LayoutObjectDrawingRecorder drawingRecorder(*paintInfo.context, m_layoutImage, paintInfo.phase, focusRect); if (drawingRecorder.canUseCachedDrawing()) return; // 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(); }
bool SVGClipPainter::drawClipAsMask(GraphicsContext& context, const LayoutObject& layoutObject, const FloatRect& targetBoundingBox, const FloatRect& targetPaintInvalidationRect, const AffineTransform& localTransform) { if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(context, layoutObject, DisplayItem::SVGClip)) return true; SkPictureBuilder maskPictureBuilder(targetPaintInvalidationRect, nullptr, &context); GraphicsContext& maskContext = maskPictureBuilder.context(); { TransformRecorder recorder(maskContext, layoutObject, localTransform); // Create a clipPathClipper if this clipPath is clipped by another clipPath. SVGResources* resources = SVGResourcesCache::cachedResourcesForLayoutObject(&m_clip); LayoutSVGResourceClipper* clipPathClipper = resources ? resources->clipper() : nullptr; ClipperState clipPathClipperState = ClipperNotApplied; if (clipPathClipper && !SVGClipPainter(*clipPathClipper).prepareEffect(m_clip, targetBoundingBox, targetPaintInvalidationRect, maskContext, clipPathClipperState)) return false; { AffineTransform contentTransform; if (m_clip.clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { contentTransform.translate(targetBoundingBox.x(), targetBoundingBox.y()); contentTransform.scaleNonUniform(targetBoundingBox.width(), targetBoundingBox.height()); } SubtreeContentTransformScope contentTransformScope(contentTransform); TransformRecorder contentTransformRecorder(maskContext, layoutObject, contentTransform); RefPtr<const SkPicture> clipContentPicture = m_clip.createContentPicture(); maskContext.getPaintController().createAndAppend<DrawingDisplayItem>(layoutObject, DisplayItem::SVGClip, clipContentPicture.get()); } if (clipPathClipper) SVGClipPainter(*clipPathClipper).finishEffect(m_clip, maskContext, clipPathClipperState); } LayoutObjectDrawingRecorder drawingRecorder(context, layoutObject, DisplayItem::SVGClip, targetPaintInvalidationRect); RefPtr<SkPicture> maskPicture = maskPictureBuilder.endRecording(); context.drawPicture(maskPicture.get()); return true; }
void VideoPainter::paintReplaced(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { WebMediaPlayer* mediaPlayer = m_layoutVideo.mediaElement()->webMediaPlayer(); bool displayingPoster = m_layoutVideo.videoElement()->shouldDisplayPosterImage(); if (!displayingPoster && !mediaPlayer) return; LayoutRect rect(m_layoutVideo.videoBox()); if (rect.isEmpty()) return; rect.moveBy(paintOffset); GraphicsContext& context = paintInfo.context; LayoutRect contentRect = m_layoutVideo.contentBoxRect(); contentRect.moveBy(paintOffset); Optional<ClipRecorder> clipRecorder; if (!contentRect.contains(rect)) { clipRecorder.emplace(context, m_layoutVideo, paintInfo.displayItemTypeForClipping(), contentRect); } if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(context, m_layoutVideo, paintInfo.phase, paintOffset)) return; LayoutObjectDrawingRecorder drawingRecorder(context, m_layoutVideo, paintInfo.phase, contentRect, paintOffset); // Video frames are only painted in software for printing or capturing node images via web APIs. bool forceSoftwareVideoPaint = paintInfo.globalPaintFlags() & GlobalPaintFlattenCompositingLayers; if (displayingPoster || !forceSoftwareVideoPaint) { // This will display the poster image, if one is present, and otherwise paint nothing. ImagePainter(m_layoutVideo).paintIntoRect(context, rect); } else { SkPaint videoPaint = context.fillPaint(); videoPaint.setColor(SK_ColorBLACK); m_layoutVideo.videoElement()->paintCurrentFrame(context.canvas(), pixelSnappedIntRect(rect), &videoPaint); } }
void VideoPainter::paintReplaced(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { WebMediaPlayer* mediaPlayer = m_layoutVideo.mediaElement()->webMediaPlayer(); bool displayingPoster = m_layoutVideo.videoElement()->shouldDisplayPosterImage(); if (!displayingPoster && !mediaPlayer) return; LayoutRect rect(m_layoutVideo.videoBox()); if (rect.isEmpty()) return; rect.moveBy(paintOffset); GraphicsContext* context = paintInfo.context; if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*context, m_layoutVideo, paintInfo.phase)) return; LayoutRect contentRect = m_layoutVideo.contentBoxRect(); contentRect.moveBy(paintOffset); LayoutObjectDrawingRecorder drawingRecorder(*context, m_layoutVideo, paintInfo.phase, contentRect); bool clip = !contentRect.contains(rect); if (clip) { context->save(); context->clip(contentRect); } if (displayingPoster) { ImagePainter(m_layoutVideo).paintIntoRect(context, rect); } else if ((m_layoutVideo.document().view() && m_layoutVideo.document().view()->paintBehavior() & PaintBehaviorFlattenCompositingLayers) || !m_layoutVideo.acceleratedRenderingInUse()) { SkPaint videoPaint = context->fillPaint(); videoPaint.setColor(SK_ColorBLACK); m_layoutVideo.videoElement()->paintCurrentFrame(context->canvas(), pixelSnappedIntRect(rect), &videoPaint); } if (clip) context->restore(); }
void WebFont::drawText(WebCanvas* canvas, const WebTextRun& run, const WebFloatPoint& leftBaseline, WebColor color, const WebRect& clip) const { FontCachePurgePreventer fontCachePurgePreventer; FloatRect textClipRect(clip); TextRun textRun(run); TextRunPaintInfo runInfo(textRun); runInfo.bounds = textClipRect; IntRect intRect(clip); SkPictureBuilder pictureBuilder(intRect); GraphicsContext& context = pictureBuilder.context(); { DrawingRecorder drawingRecorder(context, pictureBuilder, DisplayItem::WebFont, intRect); context.save(); context.setFillColor(color); context.clip(textClipRect); context.drawText(m_private->getFont(), runInfo, leftBaseline); context.restore(); } pictureBuilder.endRecording()->playback(canvas); }
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 FramePainter::paintContents(GraphicsContext& context, const GlobalPaintFlags globalPaintFlags, const IntRect& rect) { Document* document = frameView().frame().document(); #ifndef NDEBUG bool fillWithRed; if (document->printing()) fillWithRed = false; // Printing, don't fill with red (can't remember why). else if (frameView().frame().owner()) fillWithRed = false; // Subframe, don't fill with red. else if (frameView().isTransparent()) fillWithRed = false; // Transparent, don't fill with red. else if (globalPaintFlags & GlobalPaintSelectionOnly) fillWithRed = false; // Selections are transparent, don't fill with red. else fillWithRed = true; if (fillWithRed && !LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(context, *frameView().layoutView(), DisplayItem::DebugRedFill, LayoutPoint())) { IntRect contentRect(IntPoint(), frameView().contentsSize()); LayoutObjectDrawingRecorder drawingRecorder(context, *frameView().layoutView(), DisplayItem::DebugRedFill, contentRect, LayoutPoint()); } #endif LayoutView* layoutView = frameView().layoutView(); if (!layoutView) { WTF_LOG_ERROR("called FramePainter::paint with nil layoutObject"); return; } if (!frameView().shouldThrottleRendering()) { RELEASE_ASSERT(!frameView().needsLayout()); ASSERT(document->lifecycle().state() >= DocumentLifecycle::CompositingClean); } TRACE_EVENT1("devtools.timeline", "Paint", "data", InspectorPaintEvent::data(layoutView, LayoutRect(rect), 0)); bool isTopLevelPainter = !s_inPaintContents; s_inPaintContents = true; FontCachePurgePreventer fontCachePurgePreventer; // TODO(jchaffraix): GlobalPaintFlags should be const during a paint // phase. Thus we should set this flag upfront (crbug.com/510280). GlobalPaintFlags localPaintFlags = globalPaintFlags; if (document->printing()) localPaintFlags |= GlobalPaintFlattenCompositingLayers | GlobalPaintPrinting; PaintLayer* rootLayer = layoutView->layer(); #if ENABLE(ASSERT) if (!frameView().shouldThrottleRendering()) layoutView->assertSubtreeIsLaidOut(); LayoutObject::SetLayoutNeededForbiddenScope forbidSetNeedsLayout(*rootLayer->layoutObject()); #endif PaintLayerPainter layerPainter(*rootLayer); float deviceScaleFactor = blink::deviceScaleFactor(rootLayer->layoutObject()->frame()); context.setDeviceScaleFactor(deviceScaleFactor); layerPainter.paint(context, LayoutRect(rect), localPaintFlags); if (rootLayer->containsDirtyOverlayScrollbars()) layerPainter.paintOverlayScrollbars(context, LayoutRect(rect), localPaintFlags); // Regions may have changed as a result of the visibility/z-index of element changing. if (document->annotatedRegionsDirty()) frameView().updateDocumentAnnotatedRegions(); if (isTopLevelPainter) { // Everything that happens after paintContents completions is considered // to be part of the next frame. memoryCache()->updateFramePaintTimestamp(); s_inPaintContents = false; } InspectorInstrumentation::didPaint(layoutView, 0, context, LayoutRect(rect)); }
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 FramePainter::paintContents(GraphicsContext* context, const IntRect& rect) { Document* document = m_frameView.frame().document(); #ifndef NDEBUG bool fillWithRed; if (document->printing()) fillWithRed = false; // Printing, don't fill with red (can't remember why). else if (m_frameView.frame().owner()) fillWithRed = false; // Subframe, don't fill with red. else if (m_frameView.isTransparent()) fillWithRed = false; // Transparent, don't fill with red. else if (m_frameView.paintBehavior() & PaintBehaviorSelectionOnly) fillWithRed = false; // Selections are transparent, don't fill with red. else if (m_frameView.nodeToDraw()) fillWithRed = false; // Element images are transparent, don't fill with red. else fillWithRed = true; if (fillWithRed) { IntRect contentRect(IntPoint(), m_frameView.contentsSize()); DrawingRecorder drawingRecorder(*context, *m_frameView.layoutView(), DisplayItem::DebugRedFill, contentRect); if (!drawingRecorder.canUseCachedDrawing()) context->fillRect(contentRect, Color(0xFF, 0, 0)); } #endif LayoutView* layoutView = m_frameView.layoutView(); if (!layoutView) { WTF_LOG_ERROR("called FramePainter::paint with nil renderer"); return; } RELEASE_ASSERT(!m_frameView.needsLayout()); ASSERT(document->lifecycle().state() >= DocumentLifecycle::CompositingClean); TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "Paint", "data", InspectorPaintEvent::data(layoutView, LayoutRect(rect), 0)); bool isTopLevelPainter = !s_inPaintContents; s_inPaintContents = true; FontCachePurgePreventer fontCachePurgePreventer; PaintBehavior oldPaintBehavior = m_frameView.paintBehavior(); if (FrameView* parentView = m_frameView.parentFrameView()) { if (parentView->paintBehavior() & PaintBehaviorFlattenCompositingLayers) m_frameView.setPaintBehavior(m_frameView.paintBehavior() | PaintBehaviorFlattenCompositingLayers); } if (m_frameView.paintBehavior() == PaintBehaviorNormal) document->markers().invalidateRenderedRectsForMarkersInRect(LayoutRect(rect)); if (document->printing()) m_frameView.setPaintBehavior(m_frameView.paintBehavior() | PaintBehaviorFlattenCompositingLayers); ASSERT(!m_frameView.isPainting()); m_frameView.setIsPainting(true); // m_frameView.nodeToDraw() is used to draw only one element (and its descendants) LayoutObject* renderer = m_frameView.nodeToDraw() ? m_frameView.nodeToDraw()->layoutObject() : 0; DeprecatedPaintLayer* rootLayer = layoutView->layer(); #if ENABLE(ASSERT) layoutView->assertSubtreeIsLaidOut(); LayoutObject::SetLayoutNeededForbiddenScope forbidSetNeedsLayout(*rootLayer->layoutObject()); #endif DeprecatedPaintLayerPainter layerPainter(*rootLayer); float deviceScaleFactor = blink::deviceScaleFactor(rootLayer->layoutObject()->frame()); context->setDeviceScaleFactor(deviceScaleFactor); layerPainter.paint(context, LayoutRect(rect), m_frameView.paintBehavior(), renderer); if (rootLayer->containsDirtyOverlayScrollbars()) layerPainter.paintOverlayScrollbars(context, LayoutRect(rect), m_frameView.paintBehavior(), renderer); m_frameView.setIsPainting(false); m_frameView.setPaintBehavior(oldPaintBehavior); m_frameView.setLastPaintTime(currentTime()); // Regions may have changed as a result of the visibility/z-index of element changing. if (document->annotatedRegionsDirty()) m_frameView.updateAnnotatedRegions(); if (isTopLevelPainter) { // Everything that happens after paintContents completions is considered // to be part of the next frame. memoryCache()->updateFramePaintTimestamp(); s_inPaintContents = false; } InspectorInstrumentation::didPaint(layoutView, 0, context, LayoutRect(rect)); }
PassOwnPtr<DragImage> DragImage::create(const KURL& url, const String& inLabel, const FontDescription& systemFont, float deviceScaleFactor) { const Font labelFont = deriveDragLabelFont(kDragLinkLabelFontSize, FontWeightBold, systemFont); const Font urlFont = deriveDragLabelFont(kDragLinkUrlFontSize, FontWeightNormal, systemFont); FontCachePurgePreventer fontCachePurgePreventer; bool drawURLString = true; bool clipURLString = false; bool clipLabelString = false; String urlString = url.string(); String label = inLabel.stripWhiteSpace(); if (label.isEmpty()) { drawURLString = false; label = urlString; } // First step is drawing the link drag image width. TextRun labelRun(label.impl()); TextRun urlRun(urlString.impl()); IntSize labelSize(labelFont.width(labelRun), labelFont.fontMetrics().ascent() + labelFont.fontMetrics().descent()); if (labelSize.width() > kMaxDragLabelStringWidth) { labelSize.setWidth(kMaxDragLabelStringWidth); clipLabelString = true; } IntSize urlStringSize; IntSize imageSize(labelSize.width() + kDragLabelBorderX * 2, labelSize.height() + kDragLabelBorderY * 2); if (drawURLString) { urlStringSize.setWidth(urlFont.width(urlRun)); urlStringSize.setHeight(urlFont.fontMetrics().ascent() + urlFont.fontMetrics().descent()); imageSize.setHeight(imageSize.height() + urlStringSize.height()); if (urlStringSize.width() > kMaxDragLabelStringWidth) { imageSize.setWidth(kMaxDragLabelWidth); clipURLString = true; } else imageSize.setWidth(std::max(labelSize.width(), urlStringSize.width()) + kDragLabelBorderX * 2); } // We now know how big the image needs to be, so we create and // fill the background IntSize scaledImageSize = imageSize; scaledImageSize.scale(deviceScaleFactor); OwnPtr<ImageBuffer> buffer(ImageBuffer::create(scaledImageSize)); if (!buffer) return nullptr; OwnPtr<GraphicsContext> extraGraphicsContext; OwnPtr<DisplayItemList> displayItemList; GraphicsContext* context; if (RuntimeEnabledFeatures::slimmingPaintEnabled()) { displayItemList = DisplayItemList::create(); extraGraphicsContext = adoptPtr(new GraphicsContext(0, displayItemList.get())); context = extraGraphicsContext.get(); } else { context = buffer->context(); } { IntRect rect(IntPoint(), imageSize); DrawingRecorder drawingRecorder(context, buffer->displayItemClient(), DisplayItem::DragImage, rect); context->scale(deviceScaleFactor, deviceScaleFactor); const float DragLabelRadius = 5; const IntSize radii(DragLabelRadius, DragLabelRadius); const Color backgroundColor(140, 140, 140); context->fillRoundedRect(rect, radii, radii, radii, radii, backgroundColor); // Draw the text if (drawURLString) { if (clipURLString) urlString = StringTruncator::centerTruncate(urlString, imageSize.width() - (kDragLabelBorderX * 2.0f), urlFont); IntPoint textPos(kDragLabelBorderX, imageSize.height() - (kLabelBorderYOffset + urlFont.fontMetrics().descent())); TextRun textRun(urlString); context->drawText(urlFont, TextRunPaintInfo(textRun), textPos); } if (clipLabelString) label = StringTruncator::rightTruncate(label, imageSize.width() - (kDragLabelBorderX * 2.0f), labelFont); bool hasStrongDirectionality; TextRun textRun = textRunWithDirectionality(label, hasStrongDirectionality); IntPoint textPos(kDragLabelBorderX, kDragLabelBorderY + labelFont.fontDescription().computedPixelSize()); if (hasStrongDirectionality && textRun.direction() == RTL) { float textWidth = labelFont.width(textRun); int availableWidth = imageSize.width() - kDragLabelBorderX * 2; textPos.setX(availableWidth - ceilf(textWidth)); } context->drawBidiText(labelFont, TextRunPaintInfo(textRun), FloatPoint(textPos)); } if (RuntimeEnabledFeatures::slimmingPaintEnabled()) displayItemList->replay(buffer->context()); RefPtr<Image> image = buffer->copyImage(); return DragImage::create(image.get(), DoNotRespectImageOrientation, deviceScaleFactor); }