--- a/layout/svg/nsSVGIntegrationUtils.cpp
+++ b/layout/svg/nsSVGIntegrationUtils.cpp
@@ -424,100 +424,67 @@ HasNonSVGMask(const nsTArray<nsSVGMaskFr
}
}
return false;
}
typedef nsSVGIntegrationUtils::PaintFramesParams PaintFramesParams;
+/**
+ * Paint css-positioned-mask onto a given target(aMaskDT).
+ */
static DrawResult
-GenerateMaskSurface(const PaintFramesParams& aParams,
- float aOpacity, nsStyleContext* aSC,
- const nsTArray<nsSVGMaskFrame*>& aMaskFrames,
- const nsPoint& aOffsetToUserSpace,
- Matrix& aOutMaskTransform,
- RefPtr<SourceSurface>& aOutMaskSurface,
- bool& aOpacityApplied)
+PaintMaskSurface(const PaintFramesParams& aParams,
+ DrawTarget* aMaskDT, float aOpacity, nsStyleContext* aSC,
+ const nsTArray<nsSVGMaskFrame*>& aMaskFrames,
+ const gfxMatrix& aMaskSurfaceMatrix,
+ const nsPoint& aOffsetToUserSpace)
{
+ MOZ_ASSERT(aMaskFrames.Length() > 0);
+ MOZ_ASSERT(aMaskDT->GetFormat() == SurfaceFormat::A8);
+
const nsStyleSVGReset *svgReset = aSC->StyleSVGReset();
- MOZ_ASSERT(aMaskFrames.Length() > 0);
-
gfxMatrix cssPxToDevPxMatrix =
nsSVGIntegrationUtils::GetCSSPxToDevPxMatrix(aParams.frame);
- gfxContext& ctx = aParams.ctx;
-
- // There is only one SVG mask.
- if (((aMaskFrames.Length() == 1) && aMaskFrames[0])) {
- aOpacityApplied = true;
- aOutMaskSurface =
- aMaskFrames[0]->GetMaskForMaskedFrame(&ctx, aParams.frame,
- cssPxToDevPxMatrix, aOpacity,
- &aOutMaskTransform,
- svgReset->mMask.mLayers[0].mMaskMode);
- return DrawResult::SUCCESS;
- }
-
- const IntRect& maskSurfaceRect = aParams.maskRect;
- if (maskSurfaceRect.IsEmpty()) {
- return DrawResult::SUCCESS;
- }
-
- RefPtr<DrawTarget> maskDT =
- ctx.GetDrawTarget()->CreateSimilarDrawTarget(maskSurfaceRect.Size(),
- SurfaceFormat::A8);
- if (!maskDT || !maskDT->IsValid()) {
- return DrawResult::TEMPORARY_ERROR;
- }
-
- RefPtr<gfxContext> maskContext = gfxContext::CreateOrNull(maskDT);
- MOZ_ASSERT(maskContext);
-
nsPresContext* presContext = aParams.frame->PresContext();
gfxPoint devPixelOffsetToUserSpace =
nsLayoutUtils::PointToGfxPoint(aOffsetToUserSpace,
presContext->AppUnitsPerDevPixel());
- // Set ctx's matrix on maskContext, offset by the maskSurfaceRect's position.
- // This makes sure that we combine the masks in device space.
- gfxMatrix maskSurfaceMatrix =
- ctx.CurrentMatrix() * gfxMatrix::Translation(-maskSurfaceRect.TopLeft());
- maskContext->SetMatrix(maskSurfaceMatrix);
-
- // Set aAppliedOpacity as true only if all mask layers are svg mask.
- // In this case, we will apply opacity into the final mask surface, so the
- // caller does not need to apply it again.
- aOpacityApplied = !HasNonSVGMask(aMaskFrames);
+ RefPtr<gfxContext> maskContext = gfxContext::CreateOrNull(aMaskDT);
+ MOZ_ASSERT(maskContext);
+ maskContext->SetMatrix(aMaskSurfaceMatrix);
// Multiple SVG masks interleave with image mask. Paint each layer onto
- // maskDT one at a time.
+ // aMaskDT one at a time.
for (int i = aMaskFrames.Length() - 1; i >= 0 ; i--) {
nsSVGMaskFrame *maskFrame = aMaskFrames[i];
CompositionOp compositionOp = (i == int(aMaskFrames.Length() - 1))
? CompositionOp::OP_OVER
: nsCSSRendering::GetGFXCompositeMode(svgReset->mMask.mLayers[i].mComposite);
// maskFrame != nullptr means we get a SVG mask.
// maskFrame == nullptr means we get an image mask.
if (maskFrame) {
Matrix svgMaskMatrix;
RefPtr<SourceSurface> svgMask =
maskFrame->GetMaskForMaskedFrame(maskContext, aParams.frame,
cssPxToDevPxMatrix,
- aOpacityApplied ? aOpacity : 1.0,
+ aOpacity,
&svgMaskMatrix,
svgReset->mMask.mLayers[i].mMaskMode);
if (svgMask) {
gfxContextMatrixAutoSaveRestore matRestore(maskContext);
maskContext->Multiply(ThebesMatrix(svgMaskMatrix));
Rect drawRect = IntRectToRect(IntRect(IntPoint(0, 0), svgMask->GetSize()));
- maskDT->MaskSurface(ColorPattern(Color(0.0, 0.0, 0.0, 1.0)), svgMask,
+ aMaskDT->MaskSurface(ColorPattern(Color(0.0, 0.0, 0.0, 1.0)), svgMask,
drawRect.TopLeft(),
DrawOptions(1.0, compositionOp));
}
} else {
gfxContextMatrixAutoSaveRestore matRestore(maskContext);
maskContext->Multiply(gfxMatrix::Translation(-devPixelOffsetToUserSpace));
nsRenderingContext rc(maskContext);
@@ -534,16 +501,77 @@ GenerateMaskSurface(const PaintFramesPar
nsCSSRendering::PaintBackgroundWithSC(params, aSC,
*aParams.frame->StyleBorder());
if (result != DrawResult::SUCCESS) {
return result;
}
}
}
+ return DrawResult::SUCCESS;
+}
+
+static DrawResult
+CreateAndPaintMaskSurface(const PaintFramesParams& aParams,
+ float aOpacity, nsStyleContext* aSC,
+ const nsTArray<nsSVGMaskFrame*>& aMaskFrames,
+ const nsPoint& aOffsetToUserSpace,
+ Matrix& aOutMaskTransform,
+ RefPtr<SourceSurface>& aOutMaskSurface,
+ bool& aOpacityApplied)
+{
+ const nsStyleSVGReset *svgReset = aSC->StyleSVGReset();
+ MOZ_ASSERT(aMaskFrames.Length() > 0);
+
+ gfxContext& ctx = aParams.ctx;
+
+ // There is only one SVG mask.
+ if (((aMaskFrames.Length() == 1) && aMaskFrames[0])) {
+ gfxMatrix cssPxToDevPxMatrix =
+ nsSVGIntegrationUtils::GetCSSPxToDevPxMatrix(aParams.frame);
+
+ aOpacityApplied = true;
+ aOutMaskSurface =
+ aMaskFrames[0]->GetMaskForMaskedFrame(&ctx, aParams.frame,
+ cssPxToDevPxMatrix, aOpacity,
+ &aOutMaskTransform,
+ svgReset->mMask.mLayers[0].mMaskMode);
+ return DrawResult::SUCCESS;
+ }
+
+ const IntRect& maskSurfaceRect = aParams.maskRect;
+ if (maskSurfaceRect.IsEmpty()) {
+ return DrawResult::SUCCESS;
+ }
+
+ RefPtr<DrawTarget> maskDT =
+ ctx.GetDrawTarget()->CreateSimilarDrawTarget(maskSurfaceRect.Size(),
+ SurfaceFormat::A8);
+ if (!maskDT || !maskDT->IsValid()) {
+ return DrawResult::TEMPORARY_ERROR;
+ }
+
+ // Set aAppliedOpacity as true only if all mask layers are svg mask.
+ // In this case, we will apply opacity into the final mask surface, so the
+ // caller does not need to apply it again.
+ aOpacityApplied = !HasNonSVGMask(aMaskFrames);
+
+ // Set context's matrix on maskContext, offset by the maskSurfaceRect's
+ // position. This makes sure that we combine the masks in device space.
+ gfxMatrix maskSurfaceMatrix =
+ ctx.CurrentMatrix() * gfxMatrix::Translation(-aParams.maskRect.TopLeft());
+
+ DrawResult result = PaintMaskSurface(aParams, maskDT,
+ aOpacityApplied ? aOpacity : 1.0,
+ aSC, aMaskFrames, maskSurfaceMatrix,
+ aOffsetToUserSpace);
+ if (result != DrawResult::SUCCESS) {
+ return result;
+ }
+
aOutMaskTransform = ToMatrix(maskSurfaceMatrix);
if (!aOutMaskTransform.Invert()) {
return DrawResult::SUCCESS;
}
aOutMaskSurface = maskDT->Snapshot();
return DrawResult::SUCCESS;
}
@@ -752,60 +780,44 @@ nsSVGIntegrationUtils::IsMaskResourceRea
DrawResult
nsSVGIntegrationUtils::PaintMask(const PaintFramesParams& aParams)
{
MaskUsage maskUsage;
DetermineMaskUsage(aParams.frame, aParams.handleOpacity, maskUsage);
MOZ_ASSERT(maskUsage.shouldGenerateMaskLayer);
nsIFrame* frame = aParams.frame;
- DrawResult result = DrawResult::SUCCESS;
if (!ValidateSVGFrame(frame)) {
- return result;
+ return DrawResult::SUCCESS;
}
if (maskUsage.opacity == 0.0f) {
return DrawResult::SUCCESS;
}
gfxContext& ctx = aParams.ctx;
- Matrix maskTransform;
- RefPtr<SourceSurface> maskSurface;
-
gfxContextMatrixAutoSaveRestore matSR(&ctx);
nsIFrame* firstFrame =
nsLayoutUtils::FirstContinuationOrIBSplitSibling(frame);
nsSVGEffects::EffectProperties effectProperties =
nsSVGEffects::GetEffectProperties(firstFrame);
nsTArray<nsSVGMaskFrame *> maskFrames = effectProperties.GetMaskFrames();
- bool opacityApplied = false;
+ bool opacityApplied = !HasNonSVGMask(maskFrames);
nsPoint offsetToBoundingBox;
nsPoint offsetToUserSpace;
SetupContextMatrix(frame, aParams, offsetToBoundingBox,
offsetToUserSpace, false);
- result = GenerateMaskSurface(aParams, maskUsage.opacity,
- firstFrame->StyleContext(),
- maskFrames, offsetToUserSpace,
- maskTransform, maskSurface, opacityApplied);
- if (!maskSurface) {
- // Entire surface is clipped out.
- return result;
- }
- ctx.Multiply(ThebesMatrix(maskTransform));
-
- DrawTarget* target = ctx.GetDrawTarget();
- MOZ_ASSERT(target->GetFormat() == SurfaceFormat::A8);
- Rect drawingRect(Point(0, 0), Size(target->GetSize()));
- target->DrawSurface(maskSurface, drawingRect, drawingRect);
-
- return result;
+ return PaintMaskSurface(aParams, ctx.GetDrawTarget(),
+ opacityApplied ? maskUsage.opacity : 1.0,
+ firstFrame->StyleContext(), maskFrames,
+ ctx.CurrentMatrix(), offsetToUserSpace);
}
DrawResult
nsSVGIntegrationUtils::PaintMaskAndClipPath(const PaintFramesParams& aParams)
{
MOZ_ASSERT(UsingMaskOrClipPathForFrame(aParams.frame),
"Should not use this method when no mask or clipPath effect"
"on this frame");
@@ -871,20 +883,21 @@ nsSVGIntegrationUtils::PaintMaskAndClipP
if (maskUsage.shouldGenerateMaskLayer) {
matSR.SetContext(&context);
// For css-mask, we want to generate a mask for each continuation frame,
// so we setup context matrix by the position of the current frame,
// instead of the first continuation frame.
SetupContextMatrix(frame, aParams, offsetToBoundingBox,
offsetToUserSpace, false);
- result = GenerateMaskSurface(aParams, maskUsage.opacity,
- firstFrame->StyleContext(),
- maskFrames, offsetToUserSpace,
- maskTransform, maskSurface, opacityApplied);
+ result = CreateAndPaintMaskSurface(aParams, maskUsage.opacity,
+ firstFrame->StyleContext(),
+ maskFrames, offsetToUserSpace,
+ maskTransform, maskSurface,
+ opacityApplied);
if (!maskSurface) {
// Entire surface is clipped out.
return result;
}
}
if (maskUsage.shouldGenerateClipMaskLayer) {
matSR.Restore();