bool SVGClipPainter::applyClippingToContext(const LayoutObject& target, const FloatRect& targetBoundingBox, const FloatRect& paintInvalidationRect, GraphicsContext* context, ClipperState& clipperState) { ASSERT(context); ASSERT(clipperState == ClipperNotApplied); ASSERT_WITH_SECURITY_IMPLICATION(!m_clip.needsLayout()); if (paintInvalidationRect.isEmpty() || m_clip.hasCycle()) return false; SVGClipExpansionCycleHelper inClipExpansionChange(m_clip); AffineTransform animatedLocalTransform = toSVGClipPathElement(m_clip.element())->calculateAnimatedLocalTransform(); // When drawing a clip for non-SVG elements, the CTM does not include the zoom factor. // In this case, we need to apply the zoom scale explicitly - but only for clips with // userSpaceOnUse units (the zoom is accounted for objectBoundingBox-resolved lengths). if (!target.isSVG() && m_clip.clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE) { ASSERT(m_clip.style()); animatedLocalTransform.scale(m_clip.style()->effectiveZoom()); } // First, try to apply the clip as a clipPath. if (m_clip.tryPathOnlyClipping(target, context, animatedLocalTransform, targetBoundingBox)) { clipperState = ClipperAppliedPath; return true; } // Fall back to masking. clipperState = ClipperAppliedMask; // Begin compositing the clip mask. CompositingRecorder::beginCompositing(*context, target, SkXfermode::kSrcOver_Mode, 1, &paintInvalidationRect); { TransformRecorder recorder(*context, target, animatedLocalTransform); // clipPath can also be clipped by another clipPath. SVGResources* resources = SVGResourcesCache::cachedResourcesForLayoutObject(&m_clip); LayoutSVGResourceClipper* clipPathClipper = resources ? resources->clipper() : 0; ClipperState clipPathClipperState = ClipperNotApplied; if (clipPathClipper && !SVGClipPainter(*clipPathClipper).applyClippingToContext(m_clip, targetBoundingBox, paintInvalidationRect, context, clipPathClipperState)) { // End the clip mask's compositor. CompositingRecorder::endCompositing(*context, target); return false; } drawClipMaskContent(context, target, targetBoundingBox); if (clipPathClipper) SVGClipPainter(*clipPathClipper).postApplyStatefulResource(m_clip, context, clipPathClipperState); } // Masked content layer start. CompositingRecorder::beginCompositing(*context, target, SkXfermode::kSrcIn_Mode, 1, &paintInvalidationRect); return true; }
bool RenderSVGResourceClipper::applyClippingToContext(RenderObject* target, const FloatRect& targetBoundingBox, const FloatRect& repaintRect, GraphicsContext* context, ClipperContext& clipperContext) { ASSERT(target); ASSERT(context); ASSERT(clipperContext.state == ClipperContext::NotAppliedState); ASSERT_WITH_SECURITY_IMPLICATION(!needsLayout()); if (repaintRect.isEmpty() || m_inClipExpansion) return false; TemporaryChange<bool> inClipExpansionChange(m_inClipExpansion, true); // First, try to apply the clip as a clipPath. AffineTransform animatedLocalTransform = toSVGClipPathElement(element())->animatedLocalTransform(); if (tryPathOnlyClipping(context, animatedLocalTransform, targetBoundingBox)) { clipperContext.state = ClipperContext::AppliedPathState; return true; } // Fall back to masking. clipperContext.state = ClipperContext::AppliedMaskState; // Mask layer start context->beginTransparencyLayer(1, &repaintRect); { GraphicsContextStateSaver maskContentSaver(*context); context->concatCTM(animatedLocalTransform); // clipPath can also be clipped by another clipPath. SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(this); RenderSVGResourceClipper* clipPathClipper = 0; ClipperContext clipPathClipperContext; if (resources && (clipPathClipper = resources->clipper())) { if (!clipPathClipper->applyClippingToContext(this, targetBoundingBox, repaintRect, context, clipPathClipperContext)) { // FIXME: Awkward state micro-management. Ideally, GraphicsContextStateSaver should // a) pop saveLayers also // b) pop multiple states if needed (similarly to SkCanvas::restoreToCount()) // Then we should be able to replace this mess with a single, top-level GCSS. maskContentSaver.restore(); context->restoreLayer(); return false; } } drawClipMaskContent(context, targetBoundingBox); if (clipPathClipper) clipPathClipper->postApplyStatefulResource(this, context, clipPathClipperContext); } // Masked content layer start. context->beginLayer(1, CompositeSourceIn, &repaintRect); return true; }
bool SVGClipPainter::prepareEffect(const LayoutObject& target, const FloatRect& targetBoundingBox, const FloatRect& paintInvalidationRect, GraphicsContext& context, ClipperState& clipperState) { ASSERT(clipperState == ClipperNotApplied); ASSERT_WITH_SECURITY_IMPLICATION(!m_clip.needsLayout()); m_clip.clearInvalidationMask(); if (paintInvalidationRect.isEmpty() || m_clip.hasCycle()) return false; SVGClipExpansionCycleHelper inClipExpansionChange(m_clip); AffineTransform animatedLocalTransform = toSVGClipPathElement(m_clip.element())->calculateAnimatedLocalTransform(); // When drawing a clip for non-SVG elements, the CTM does not include the zoom factor. // In this case, we need to apply the zoom scale explicitly - but only for clips with // userSpaceOnUse units (the zoom is accounted for objectBoundingBox-resolved lengths). if (!target.isSVG() && m_clip.clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE) { ASSERT(m_clip.style()); animatedLocalTransform.scale(m_clip.style()->effectiveZoom()); } // First, try to apply the clip as a clipPath. Path clipPath; if (m_clip.asPath(animatedLocalTransform, targetBoundingBox, clipPath)) { clipperState = ClipperAppliedPath; context.getPaintController().createAndAppend<BeginClipPathDisplayItem>(target, clipPath); return true; } // Fall back to masking. clipperState = ClipperAppliedMask; // Begin compositing the clip mask. CompositingRecorder::beginCompositing(context, target, SkXfermode::kSrcOver_Mode, 1, &paintInvalidationRect); { if (!drawClipAsMask(context, target, targetBoundingBox, paintInvalidationRect, animatedLocalTransform)) { // End the clip mask's compositor. CompositingRecorder::endCompositing(context, target); return false; } } // Masked content layer start. CompositingRecorder::beginCompositing(context, target, SkXfermode::kSrcIn_Mode, 1, &paintInvalidationRect); return true; }
bool RenderSVGResourceClipper::applyClippingToContext(RenderObject* target, const FloatRect& targetBoundingBox, const FloatRect& paintInvalidationRect, GraphicsContext* context, ClipperState& clipperState) { ASSERT(target); ASSERT(context); ASSERT(clipperState == ClipperNotApplied); ASSERT_WITH_SECURITY_IMPLICATION(!needsLayout()); if (paintInvalidationRect.isEmpty() || m_inClipExpansion) return false; TemporaryChange<bool> inClipExpansionChange(m_inClipExpansion, true); AffineTransform animatedLocalTransform = toSVGClipPathElement(element())->animatedLocalTransform(); // When drawing a clip for non-SVG elements, the CTM does not include the zoom factor. // In this case, we need to apply the zoom scale explicitly - but only for clips with // userSpaceOnUse units (the zoom is accounted for objectBoundingBox-resolved lengths). if (!target->isSVG() && clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE) { ASSERT(style()); animatedLocalTransform.scale(style()->effectiveZoom()); } // First, try to apply the clip as a clipPath. if (tryPathOnlyClipping(context, animatedLocalTransform, targetBoundingBox)) { clipperState = ClipperAppliedPath; return true; } // Fall back to masking. clipperState = ClipperAppliedMask; // Mask layer start context->beginTransparencyLayer(1, &paintInvalidationRect); { GraphicsContextStateSaver maskContentSaver(*context); context->concatCTM(animatedLocalTransform); // clipPath can also be clipped by another clipPath. SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(this); RenderSVGResourceClipper* clipPathClipper = resources ? resources->clipper() : 0; ClipperState clipPathClipperState = ClipperNotApplied; if (clipPathClipper && !clipPathClipper->applyClippingToContext(this, targetBoundingBox, paintInvalidationRect, context, clipPathClipperState)) { // FIXME: Awkward state micro-management. Ideally, GraphicsContextStateSaver should // a) pop saveLayers also // b) pop multiple states if needed (similarly to SkCanvas::restoreToCount()) // Then we should be able to replace this mess with a single, top-level GCSS. maskContentSaver.restore(); context->restoreLayer(); return false; } drawClipMaskContent(context, targetBoundingBox); if (clipPathClipper) clipPathClipper->postApplyStatefulResource(this, context, clipPathClipperState); } // Masked content layer start. context->beginLayer(1, CompositeSourceIn, &paintInvalidationRect); return true; }
bool SVGClipPainter::prepareEffect(const LayoutObject& target, const FloatRect& targetBoundingBox, const FloatRect& visualRect, const FloatPoint& layerPositionOffset, GraphicsContext& context, ClipperState& clipperState) { DCHECK_EQ(clipperState, ClipperState::NotApplied); SECURITY_DCHECK(!m_clip.needsLayout()); m_clip.clearInvalidationMask(); if (m_clip.hasCycle()) return false; SVGClipExpansionCycleHelper inClipExpansionChange(m_clip); AffineTransform animatedLocalTransform = toSVGClipPathElement(m_clip.element()) ->calculateTransform(SVGElement::IncludeMotionTransform); // When drawing a clip for non-SVG elements, the CTM does not include the zoom // factor. In this case, we need to apply the zoom scale explicitly - but // only for clips with userSpaceOnUse units (the zoom is accounted for // objectBoundingBox-resolved lengths). if (!target.isSVG() && m_clip.clipPathUnits() == SVGUnitTypes::kSvgUnitTypeUserspaceonuse) { DCHECK(m_clip.style()); animatedLocalTransform.scale(m_clip.style()->effectiveZoom()); } // First, try to apply the clip as a clipPath. Path clipPath; if (m_clip.asPath(animatedLocalTransform, targetBoundingBox, clipPath)) { AffineTransform positionTransform; positionTransform.translate(layerPositionOffset.x(), layerPositionOffset.y()); clipPath.transform(positionTransform); clipperState = ClipperState::AppliedPath; context.getPaintController().createAndAppend<BeginClipPathDisplayItem>( target, clipPath); return true; } // Fall back to masking. clipperState = ClipperState::AppliedMask; // Begin compositing the clip mask. CompositingRecorder::beginCompositing(context, target, SkBlendMode::kSrcOver, 1, &visualRect); { if (!drawClipAsMask(context, target, targetBoundingBox, visualRect, animatedLocalTransform, layerPositionOffset)) { // End the clip mask's compositor. CompositingRecorder::endCompositing(context, target); return false; } } // Masked content layer start. CompositingRecorder::beginCompositing(context, target, SkBlendMode::kSrcIn, 1, &visualRect); return true; }