void SVGShapePainter::paintMarkers(const PaintInfo& paintInfo, const FloatRect& boundingBox) { const Vector<MarkerPosition>* markerPositions = m_layoutSVGShape.markerPositions(); if (!markerPositions || markerPositions->isEmpty()) return; SVGResources* resources = SVGResourcesCache::cachedResourcesForLayoutObject(&m_layoutSVGShape); if (!resources) return; LayoutSVGResourceMarker* markerStart = resources->markerStart(); LayoutSVGResourceMarker* markerMid = resources->markerMid(); LayoutSVGResourceMarker* markerEnd = resources->markerEnd(); if (!markerStart && !markerMid && !markerEnd) return; float strokeWidth = m_layoutSVGShape.strokeWidth(); unsigned size = markerPositions->size(); for (unsigned i = 0; i < size; ++i) { if (LayoutSVGResourceMarker* marker = SVGMarkerData::markerForType((*markerPositions)[i].type, markerStart, markerMid, markerEnd)) { SkPictureBuilder pictureBuilder(boundingBox, nullptr, &paintInfo.context); PaintInfo markerPaintInfo(pictureBuilder.context(), paintInfo); // It's expensive to track the transformed paint cull rect for each // marker so just disable culling. The shape paint call will already // be culled if it is outside the paint info cull rect. markerPaintInfo.m_cullRect.m_rect = LayoutRect::infiniteIntRect(); paintMarker(markerPaintInfo, *marker, (*markerPositions)[i], strokeWidth); pictureBuilder.endRecording()->playback(paintInfo.context.canvas()); } } }
PassRefPtr<SkPicture> LayoutSVGResourcePattern::asPicture(const FloatRect& tileBounds, const AffineTransform& tileTransform) const { ASSERT(!m_shouldCollectPatternAttributes); AffineTransform contentTransform; if (attributes().patternContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) contentTransform = tileTransform; FloatRect bounds(FloatPoint(), tileBounds.size()); SkPictureBuilder pictureBuilder(bounds); const LayoutSVGResourceContainer* patternLayoutObject = resolveContentElement(); ASSERT(patternLayoutObject && !patternLayoutObject->needsLayout()); SubtreeContentTransformScope contentTransformScope(contentTransform); { TransformRecorder transformRecorder(pictureBuilder.context(), *patternLayoutObject, tileTransform); for (LayoutObject* child = patternLayoutObject->firstChild(); child; child = child->nextSibling()) SVGPaintContext::paintSubtree(pictureBuilder.context(), child); } return pictureBuilder.endRecording(); }
sk_sp<const SkPicture> LayoutSVGResourceClipper::createContentPicture() { ASSERT(frame()); if (m_clipContentPicture) return m_clipContentPicture; // Using strokeBoundingBox (instead of visualRectInLocalSVGCoordinates) to // avoid the intersection with local clips/mask, which may yield incorrect // results when mixing objectBoundingBox and userSpaceOnUse units // (http://crbug.com/294900). FloatRect bounds = strokeBoundingBox(); SkPictureBuilder pictureBuilder(bounds, nullptr, nullptr); // Switch to a paint behavior where all children of this <clipPath> will be // laid out using special constraints: // - fill-opacity/stroke-opacity/opacity set to 1 // - masker/filter not applied when laying out the children // - fill is set to the initial fill paint server (solid, black) // - stroke is set to the initial stroke paint server (none) PaintInfo info(pictureBuilder.context(), LayoutRect::infiniteIntRect(), PaintPhaseForeground, GlobalPaintNormalPhase, PaintLayerPaintingRenderingClipPathAsMask); for (const SVGElement& childElement : Traversal<SVGElement>::childrenOf(*element())) { if (!contributesToClip(childElement)) continue; // Use the LayoutObject of the direct child even if it is a <use>. In that // case, we will paint the targeted element indirectly. const LayoutObject* layoutObject = childElement.layoutObject(); layoutObject->paint(info, IntPoint()); } m_clipContentPicture = pictureBuilder.endRecording(); return m_clipContentPicture; }
void printSinglePage(SkCanvas& canvas) { IntRect pageRect(0, 0, kPageWidth, kPageHeight); printContext().begin(pageRect.width(), pageRect.height()); document().view()->updateAllLifecyclePhases(); SkPictureBuilder pictureBuilder(pageRect); GraphicsContext& context = pictureBuilder.context(); context.setPrinting(true); document().view()->paintContents(&context, GlobalPaintPrinting, pageRect); pictureBuilder.endRecording()->playback(&canvas); printContext().outputLinkedDestinations(&canvas, pageRect); printContext().end(); }
sk_sp<const SkPicture> LayoutSVGResourceMasker::createContentPicture( AffineTransform& contentTransformation, const FloatRect& targetBoundingBox, GraphicsContext& context) { SVGUnitTypes::SVGUnitType contentUnits = toSVGMaskElement(element()) ->maskContentUnits() ->currentValue() ->enumValue(); if (contentUnits == SVGUnitTypes::kSvgUnitTypeObjectboundingbox) { contentTransformation.translate(targetBoundingBox.x(), targetBoundingBox.y()); contentTransformation.scaleNonUniform(targetBoundingBox.width(), targetBoundingBox.height()); } if (m_maskContentPicture) return m_maskContentPicture; SubtreeContentTransformScope contentTransformScope(contentTransformation); // Using strokeBoundingBox instead of visualRectInLocalCoordinates // to avoid the intersection with local clips/mask, which may yield incorrect // results when mixing objectBoundingBox and userSpaceOnUse units. // http://crbug.com/294900 FloatRect bounds = strokeBoundingBox(); SkPictureBuilder pictureBuilder(bounds, nullptr, &context); ColorFilter maskContentFilter = style()->svgStyle().colorInterpolation() == CI_LINEARRGB ? ColorFilterSRGBToLinearRGB : ColorFilterNone; pictureBuilder.context().setColorFilter(maskContentFilter); for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()); childElement; childElement = Traversal<SVGElement>::nextSibling(*childElement)) { LayoutObject* layoutObject = childElement->layoutObject(); if (!layoutObject) continue; const ComputedStyle* style = layoutObject->style(); if (!style || style->display() == EDisplay::None || style->visibility() != EVisibility::Visible) continue; SVGPaintContext::paintSubtree(pictureBuilder.context(), layoutObject); } m_maskContentPicture = pictureBuilder.endRecording(); return m_maskContentPicture; }
void InspectorLayerTreeAgent::makeSnapshot(ErrorString* errorString, const String& layerId, String* snapshotId) { GraphicsLayer* layer = layerById(errorString, layerId); if (!layer) return; IntSize size = expandedIntSize(layer->size()); SkPictureBuilder pictureBuilder(FloatRect(0, 0, size.width(), size.height())); layer->paint(pictureBuilder.context(), IntRect(IntPoint(0, 0), size)); RefPtr<PictureSnapshot> snapshot = adoptRef(new PictureSnapshot(pictureBuilder.endRecording())); *snapshotId = String::number(++s_lastSnapshotId); bool newEntry = m_snapshotById.add(*snapshotId, snapshot).isNewEntry; ASSERT_UNUSED(newEntry, newEntry); }
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); }
PassRefPtr<const SkPicture> LayoutSVGResourceClipper::createContentPicture(AffineTransform& contentTransformation, const FloatRect& targetBoundingBox, GraphicsContext& context) { ASSERT(frame()); if (clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { contentTransformation.translate(targetBoundingBox.x(), targetBoundingBox.y()); contentTransformation.scaleNonUniform(targetBoundingBox.width(), targetBoundingBox.height()); } if (m_clipContentPicture) return m_clipContentPicture; SubtreeContentTransformScope contentTransformScope(contentTransformation); // Using strokeBoundingBox (instead of paintInvalidationRectInLocalCoordinates) to avoid the intersection // with local clips/mask, which may yield incorrect results when mixing objectBoundingBox and // userSpaceOnUse units (http://crbug.com/294900). FloatRect bounds = strokeBoundingBox(); SkPictureBuilder pictureBuilder(bounds, nullptr, &context); for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()); childElement; childElement = Traversal<SVGElement>::nextSibling(*childElement)) { LayoutObject* layoutObject = childElement->layoutObject(); if (!layoutObject) continue; const ComputedStyle* style = layoutObject->style(); if (!style || style->display() == NONE || style->visibility() != VISIBLE) continue; bool isUseElement = isSVGUseElement(*childElement); if (isUseElement) { const SVGGraphicsElement* clippingElement = toSVGUseElement(*childElement).targetGraphicsElementForClipping(); if (!clippingElement) continue; layoutObject = clippingElement->layoutObject(); if (!layoutObject) continue; } // Only shapes, paths and texts are allowed for clipping. if (!layoutObject->isSVGShape() && !layoutObject->isSVGText()) continue; if (isUseElement) layoutObject = childElement->layoutObject(); // Switch to a paint behavior where all children of this <clipPath> will be laid out using special constraints: // - fill-opacity/stroke-opacity/opacity set to 1 // - masker/filter not applied when laying out the children // - fill is set to the initial fill paint server (solid, black) // - stroke is set to the initial stroke paint server (none) PaintInfo info(pictureBuilder.context(), LayoutRect::infiniteIntRect(), PaintPhaseForeground, GlobalPaintNormalPhase, PaintLayerPaintingRenderingClipPathAsMask); layoutObject->paint(info, IntPoint()); } m_clipContentPicture = pictureBuilder.endRecording(); return m_clipContentPicture; }