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 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 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; }