PassRefPtr<DisplayList> RenderSVGResourcePattern::asDisplayList(const FloatRect& tileBounds, const AffineTransform& tileTransform) const { ASSERT(!m_shouldCollectPatternAttributes); AffineTransform contentTransform; if (m_attributes.patternContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) contentTransform = tileTransform; // Draw the content into a DisplayList. GraphicsContext recordingContext(nullptr); recordingContext.beginRecording(FloatRect(FloatPoint(), tileBounds.size())); recordingContext.concatCTM(tileTransform); ASSERT(m_attributes.patternContentElement()); RenderSVGResourceContainer* patternRenderer = toRenderSVGResourceContainer(m_attributes.patternContentElement()->renderer()); ASSERT(patternRenderer); ASSERT(!patternRenderer->needsLayout()); SubtreeContentTransformScope contentTransformScope(contentTransform); for (RenderObject* child = patternRenderer->firstChild(); child; child = child->nextSibling()) SVGRenderingContext::renderSubtree(&recordingContext, child); return recordingContext.endRecording(); }
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> 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; }
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 RenderSVGResourceClipper::drawClipMaskContent(GraphicsContext* context, const FloatRect& targetBoundingBox) { ASSERT(context); AffineTransform contentTransformation; if (clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { contentTransformation.translate(targetBoundingBox.x(), targetBoundingBox.y()); contentTransformation.scaleNonUniform(targetBoundingBox.width(), targetBoundingBox.height()); context->concatCTM(contentTransformation); } if (!m_clipContentPicture) { SubtreeContentTransformScope contentTransformScope(contentTransformation); createPicture(context); } context->drawPicture(m_clipContentPicture.get()); }
PassRefPtr<const SkPicture> LayoutSVGResourceMasker::createContentPicture(AffineTransform& contentTransformation, const FloatRect& targetBoundingBox) { SVGUnitTypes::SVGUnitType contentUnits = toSVGMaskElement(element())->maskContentUnits()->currentValue()->enumValue(); if (contentUnits == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { 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 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(); OwnPtr<DisplayItemList> displayItemList; if (RuntimeEnabledFeatures::slimmingPaintEnabled()) displayItemList = DisplayItemList::create(); GraphicsContext context(nullptr, displayItemList.get()); context.beginRecording(bounds); ColorFilter maskContentFilter = style()->svgStyle().colorInterpolation() == CI_LINEARRGB ? ColorFilterSRGBToLinearRGB : ColorFilterNone; 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() == NONE || style->visibility() != VISIBLE) continue; SVGPaintContext::paintSubtree(&context, layoutObject); } if (displayItemList) displayItemList->commitNewDisplayItemsAndReplay(context); m_maskContentPicture = context.endRecording(); return m_maskContentPicture; }
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; }
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; }