void RenderSVGResourceMasker::postApplyResource(RenderObject* object, GraphicsContext*& context) { ASSERT(object); ASSERT(context); ASSERT(style()); ASSERT_WITH_SECURITY_IMPLICATION(!needsLayout()); FloatRect paintInvalidationRect = object->paintInvalidationRectInLocalCoordinates(); const SVGRenderStyle& svgStyle = style()->svgStyle(); ColorFilter maskLayerFilter = svgStyle.maskType() == MT_LUMINANCE ? ColorFilterLuminanceToAlpha : ColorFilterNone; ColorFilter maskContentFilter = svgStyle.colorInterpolation() == CI_LINEARRGB ? ColorFilterSRGBToLinearRGB : ColorFilterNone; // Mask layer start. context->beginLayer(1, CompositeDestinationIn, &paintInvalidationRect, maskLayerFilter); { // Draw the mask with color conversion (when needed). GraphicsContextStateSaver maskContentSaver(*context); context->setColorFilter(maskContentFilter); drawMaskForRenderer(context, object->objectBoundingBox()); } // Transfer mask layer -> content layer (DstIn) context->endLayer(); // Transfer content layer -> backdrop (SrcOver) context->endLayer(); }
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 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; }