bool RenderSVGResourceClipper::applyClippingToContext(RenderObject* object, const FloatRect& objectBoundingBox, const FloatRect& repaintRect, GraphicsContext* context) { bool missingClipperData = !m_clipper.contains(object); if (missingClipperData) m_clipper.set(object, new ClipperData); bool shouldCreateClipData = false; AffineTransform animatedLocalTransform = static_cast<SVGClipPathElement*>(node())->animatedLocalTransform(); ClipperData* clipperData = m_clipper.get(object); if (!clipperData->clipMaskImage) { if (pathOnlyClipping(context, animatedLocalTransform, objectBoundingBox)) return true; shouldCreateClipData = true; } AffineTransform absoluteTransform; SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(object, absoluteTransform); if (shouldCreateClipData && !repaintRect.isEmpty()) { if (!SVGRenderingContext::createImageBuffer(repaintRect, absoluteTransform, clipperData->clipMaskImage, ColorSpaceDeviceRGB, Unaccelerated)) return false; GraphicsContext* maskContext = clipperData->clipMaskImage->context(); ASSERT(maskContext); maskContext->concatCTM(animatedLocalTransform); // clipPath can also be clipped by another clipPath. SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(this); RenderSVGResourceClipper* clipper; bool succeeded; if (resources && (clipper = resources->clipper())) { GraphicsContextStateSaver stateSaver(*maskContext); if (!clipper->applyClippingToContext(this, objectBoundingBox, repaintRect, maskContext)) return false; succeeded = drawContentIntoMaskImage(clipperData, objectBoundingBox); // The context restore applies the clipping on non-CG platforms. } else succeeded = drawContentIntoMaskImage(clipperData, objectBoundingBox); if (!succeeded) clipperData->clipMaskImage.clear(); } if (!clipperData->clipMaskImage) return false; SVGRenderingContext::clipToImageBuffer(context, absoluteTransform, repaintRect, clipperData->clipMaskImage, missingClipperData); return true; }
bool RenderSVGResourceMasker::applyResource(RenderElement& renderer, const RenderStyle&, GraphicsContext*& context, unsigned short resourceMode) { ASSERT(context); ASSERT_UNUSED(resourceMode, resourceMode == ApplyToDefaultMode); bool missingMaskerData = !m_masker.contains(&renderer); if (missingMaskerData) m_masker.set(&renderer, std::make_unique<MaskerData>()); MaskerData* maskerData = m_masker.get(&renderer); AffineTransform absoluteTransform = SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(renderer); FloatRect repaintRect = renderer.repaintRectInLocalCoordinates(); if (!maskerData->maskImage && !repaintRect.isEmpty()) { const SVGRenderStyle& svgStyle = style().svgStyle(); ColorSpace colorSpace = svgStyle.colorInterpolation() == CI_LINEARRGB ? ColorSpaceLinearRGB : ColorSpaceDeviceRGB; maskerData->maskImage = SVGRenderingContext::createImageBuffer(repaintRect, absoluteTransform, colorSpace, Unaccelerated); if (!maskerData->maskImage) return false; if (!drawContentIntoMaskImage(maskerData, colorSpace, &renderer)) maskerData->maskImage.reset(); } if (!maskerData->maskImage) return false; SVGRenderingContext::clipToImageBuffer(context, absoluteTransform, repaintRect, maskerData->maskImage, missingMaskerData); return true; }
bool RenderSVGResourceClipper::applyClippingToContext(RenderElement& renderer, const FloatRect& objectBoundingBox, const FloatRect& repaintRect, GraphicsContext& context) { ClipperMaskImage& clipperMaskImage = addRendererToClipper(renderer); bool shouldCreateClipperMaskImage = !clipperMaskImage; AffineTransform animatedLocalTransform = clipPathElement().animatedLocalTransform(); if (shouldCreateClipperMaskImage && pathOnlyClipping(context, animatedLocalTransform, objectBoundingBox)) return true; AffineTransform absoluteTransform = SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(renderer); if (shouldCreateClipperMaskImage && !repaintRect.isEmpty()) { // FIXME (149469): This image buffer should not be unconditionally unaccelerated. Making it match the context breaks nested clipping, though. clipperMaskImage = SVGRenderingContext::createImageBuffer(repaintRect, absoluteTransform, ColorSpaceSRGB, Unaccelerated); if (!clipperMaskImage) return false; GraphicsContext& maskContext = clipperMaskImage->context(); maskContext.concatCTM(animatedLocalTransform); // clipPath can also be clipped by another clipPath. auto* resources = SVGResourcesCache::cachedResourcesForRenderer(*this); RenderSVGResourceClipper* clipper; bool succeeded; if (resources && (clipper = resources->clipper())) { GraphicsContextStateSaver stateSaver(maskContext); if (!clipper->applyClippingToContext(*this, objectBoundingBox, repaintRect, maskContext)) return false; succeeded = drawContentIntoMaskImage(clipperMaskImage, objectBoundingBox); // The context restore applies the clipping on non-CG platforms. } else succeeded = drawContentIntoMaskImage(clipperMaskImage, objectBoundingBox); if (!succeeded) clipperMaskImage.reset(); } if (!clipperMaskImage) return false; SVGRenderingContext::clipToImageBuffer(context, absoluteTransform, repaintRect, clipperMaskImage, shouldCreateClipperMaskImage); return true; }
bool RenderSVGResourceClipper::applyClippingToContext(RenderObject* object, const FloatRect& objectBoundingBox, const FloatRect& repaintRect, GraphicsContext* context) { if (!m_clipper.contains(object)) m_clipper.set(object, new ClipperData); bool shouldCreateClipData = false; ClipperData* clipperData = m_clipper.get(object); if (!clipperData->clipMaskImage) { if (pathOnlyClipping(context, objectBoundingBox)) return true; shouldCreateClipData = true; } AffineTransform absoluteTransform; SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(object, absoluteTransform); FloatRect absoluteTargetRect = absoluteTransform.mapRect(repaintRect); FloatRect clampedAbsoluteTargetRect = SVGImageBufferTools::clampedAbsoluteTargetRectForRenderer(object, absoluteTargetRect); if (shouldCreateClipData && !clampedAbsoluteTargetRect.isEmpty()) { if (!SVGImageBufferTools::createImageBuffer(absoluteTargetRect, clampedAbsoluteTargetRect, clipperData->clipMaskImage, ColorSpaceDeviceRGB)) return false; GraphicsContext* maskContext = clipperData->clipMaskImage->context(); ASSERT(maskContext); // The save/restore pair is needed for clipToImageBuffer - it doesn't work without it on non-Cg platforms. maskContext->save(); maskContext->translate(-clampedAbsoluteTargetRect.x(), -clampedAbsoluteTargetRect.y()); maskContext->concatCTM(absoluteTransform); // clipPath can also be clipped by another clipPath. if (SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(this)) { if (RenderSVGResourceClipper* clipper = resources->clipper()) { if (!clipper->applyClippingToContext(this, objectBoundingBox, repaintRect, maskContext)) { maskContext->restore(); return false; } } } drawContentIntoMaskImage(clipperData, objectBoundingBox); maskContext->restore(); } if (!clipperData->clipMaskImage) return false; SVGImageBufferTools::clipToImageBuffer(context, absoluteTransform, clampedAbsoluteTargetRect, clipperData->clipMaskImage); return true; }
bool RenderSVGResourceMasker::applyResource(RenderObject* object, RenderStyle*, GraphicsContext*& context, unsigned short resourceMode) { ASSERT(object); ASSERT(context); #ifndef NDEBUG ASSERT(resourceMode == ApplyToDefaultMode); #else UNUSED_PARAM(resourceMode); #endif if (!m_masker.contains(object)) m_masker.set(object, new MaskerData); MaskerData* maskerData = m_masker.get(object); AffineTransform absoluteTransform; SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(object, absoluteTransform); FloatRect absoluteTargetRect = absoluteTransform.mapRect(object->repaintRectInLocalCoordinates()); FloatRect clampedAbsoluteTargetRect = SVGImageBufferTools::clampedAbsoluteTargetRect(absoluteTargetRect); if (!maskerData->maskImage && !clampedAbsoluteTargetRect.isEmpty()) { SVGMaskElement* maskElement = static_cast<SVGMaskElement*>(node()); if (!maskElement) return false; ASSERT(style()); const SVGRenderStyle* svgStyle = style()->svgStyle(); ASSERT(svgStyle); ColorSpace colorSpace = svgStyle->colorInterpolation() == CI_LINEARRGB ? ColorSpaceLinearRGB : ColorSpaceDeviceRGB; if (!SVGImageBufferTools::createImageBuffer(absoluteTargetRect, clampedAbsoluteTargetRect, maskerData->maskImage, colorSpace)) return false; GraphicsContext* maskImageContext = maskerData->maskImage->context(); ASSERT(maskImageContext); // The save/restore pair is needed for clipToImageBuffer - it doesn't work without it on non-Cg platforms. maskImageContext->save(); maskImageContext->translate(-clampedAbsoluteTargetRect.x(), -clampedAbsoluteTargetRect.y()); maskImageContext->concatCTM(absoluteTransform); drawContentIntoMaskImage(maskerData, colorSpace, maskElement, object); } if (!maskerData->maskImage) return false; SVGImageBufferTools::clipToImageBuffer(context, absoluteTransform, clampedAbsoluteTargetRect, maskerData->maskImage); return true; }
bool RenderSVGResourceMasker::applyResource(RenderObject* object, RenderStyle*, GraphicsContext*& context, unsigned short resourceMode) { ASSERT(object); ASSERT(context); ASSERT_UNUSED(resourceMode, resourceMode == ApplyToDefaultMode); bool missingMaskerData = !m_masker.contains(object); if (missingMaskerData) m_masker.set(object, new MaskerData); MaskerData* maskerData = m_masker.get(object); AffineTransform absoluteTransform; SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(object, absoluteTransform); FloatRect repaintRect = object->repaintRectInLocalCoordinates(); if (!maskerData->maskImage && !repaintRect.isEmpty()) { SVGMaskElement* maskElement = static_cast<SVGMaskElement*>(node()); if (!maskElement) return false; ASSERT(style()); const SVGRenderStyle* svgStyle = style()->svgStyle(); ASSERT(svgStyle); ColorSpace colorSpace = svgStyle->colorInterpolation() == CI_LINEARRGB ? ColorSpaceLinearRGB : ColorSpaceDeviceRGB; if (!SVGImageBufferTools::createImageBuffer(repaintRect, absoluteTransform, maskerData->maskImage, colorSpace, Unaccelerated)) return false; if (!drawContentIntoMaskImage(maskerData, colorSpace, maskElement, object)) { maskerData->maskImage.clear(); } } if (!maskerData->maskImage) return false; SVGImageBufferTools::clipToImageBuffer(context, absoluteTransform, repaintRect, maskerData->maskImage, missingMaskerData); return true; }