From 92a1ecae0da7674ff568c851f471c4ae7c726b57 Mon Sep 17 00:00:00 2001 From: cku Date: Fri, 4 Nov 2016 14:48:11 +0800 Subject: [PATCH] Bug 1313898 - Part 2. Paint non-trivial clip-path onto mask layer. r=mstange MozReview-Commit-ID: HJUwhqsJ42M --HG-- extra : rebase_source : 503b69a17e69b24c88830ae866c6d8aecc7baeb2 --- layout/base/nsDisplayList.cpp | 11 ++-- layout/svg/nsSVGIntegrationUtils.cpp | 88 ++++++++++++++++++++++------ 2 files changed, 77 insertions(+), 22 deletions(-) diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 56a06db9c8ac..a26d0fa04f66 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -7140,10 +7140,13 @@ bool nsDisplayMask::ShouldPaintOnMaskLayer(LayerManager* aManager) nsSVGUtils::MaskUsage maskUsage; nsSVGUtils::DetermineMaskUsage(mFrame, mHandleOpacity, maskUsage); - if (!maskUsage.shouldGenerateMaskLayer || - maskUsage.opacity != 1.0 || maskUsage.shouldApplyClipPath || - maskUsage.shouldApplyBasicShape || - maskUsage.shouldGenerateClipMaskLayer) { + if (!maskUsage.shouldGenerateMaskLayer && + !maskUsage.shouldGenerateClipMaskLayer) { + return false; + } + + if (maskUsage.opacity != 1.0 || maskUsage.shouldApplyClipPath || + maskUsage.shouldApplyBasicShape) { return false; } diff --git a/layout/svg/nsSVGIntegrationUtils.cpp b/layout/svg/nsSVGIntegrationUtils.cpp index b36e999a454d..4f95c84bc049 100644 --- a/layout/svg/nsSVGIntegrationUtils.cpp +++ b/layout/svg/nsSVGIntegrationUtils.cpp @@ -478,10 +478,9 @@ PaintMaskSurface(const PaintFramesParams& aParams, gfxContextMatrixAutoSaveRestore matRestore(maskContext); maskContext->Multiply(ThebesMatrix(svgMaskMatrix)); - Rect drawRect = IntRectToRect(IntRect(IntPoint(0, 0), svgMask->GetSize())); aMaskDT->MaskSurface(ColorPattern(Color(0.0, 0.0, 0.0, 1.0)), svgMask, - drawRect.TopLeft(), - DrawOptions(1.0, compositionOp)); + Point(0, 0), + DrawOptions(1.0, compositionOp)); } } else { gfxContextMatrixAutoSaveRestore matRestore(maskContext); @@ -704,7 +703,8 @@ nsSVGIntegrationUtils::PaintMask(const PaintFramesParams& aParams) nsSVGUtils::MaskUsage maskUsage; nsSVGUtils::DetermineMaskUsage(aParams.frame, aParams.handleOpacity, maskUsage); - MOZ_ASSERT(maskUsage.shouldGenerateMaskLayer); + MOZ_ASSERT(maskUsage.shouldGenerateMaskLayer || + maskUsage.shouldGenerateClipMaskLayer); nsIFrame* frame = aParams.frame; if (!ValidateSVGFrame(frame)) { @@ -716,25 +716,77 @@ nsSVGIntegrationUtils::PaintMask(const PaintFramesParams& aParams) } gfxContext& ctx = aParams.ctx; - - gfxContextMatrixAutoSaveRestore matSR(&ctx); - nsIFrame* firstFrame = nsLayoutUtils::FirstContinuationOrIBSplitSibling(frame); nsSVGEffects::EffectProperties effectProperties = nsSVGEffects::GetEffectProperties(firstFrame); - nsTArray maskFrames = effectProperties.GetMaskFrames(); - bool opacityApplied = !HasNonSVGMask(maskFrames); + DrawResult result = DrawResult::SUCCESS; nsPoint offsetToBoundingBox; nsPoint offsetToUserSpace; - SetupContextMatrix(frame, aParams, offsetToBoundingBox, - offsetToUserSpace, false); + gfxContextMatrixAutoSaveRestore matSR; + DrawTarget* target = ctx.GetDrawTarget(); - return PaintMaskSurface(aParams, ctx.GetDrawTarget(), - opacityApplied ? maskUsage.opacity : 1.0, - firstFrame->StyleContext(), maskFrames, - ctx.CurrentMatrix(), offsetToUserSpace); + // Paint mask onto ctx. + if (maskUsage.shouldGenerateMaskLayer) { + matSR.SetContext(&ctx); + + SetupContextMatrix(frame, aParams, offsetToBoundingBox, + offsetToUserSpace, false); + nsTArray maskFrames = effectProperties.GetMaskFrames(); + bool opacityApplied = !HasNonSVGMask(maskFrames); + result = PaintMaskSurface(aParams, target, + opacityApplied ? maskUsage.opacity : 1.0, + firstFrame->StyleContext(), maskFrames, + ctx.CurrentMatrix(), offsetToUserSpace); + if (result != DrawResult::SUCCESS) { + return result; + } + } + + // Paint clip-path onto ctx. + if (maskUsage.shouldGenerateClipMaskLayer) { + matSR.Restore(); + matSR.SetContext(&ctx); + + SetupContextMatrix(firstFrame, aParams, offsetToBoundingBox, + offsetToUserSpace, false); + Matrix clipMaskTransform; + gfxMatrix cssPxToDevPxMatrix = GetCSSPxToDevPxMatrix(frame); + + bool isOK = true; + nsSVGClipPathFrame *clipPathFrame = + effectProperties.GetClipPathFrame(&isOK); + // XXX Bug 1317636. Split nsSVGClipPathFrame::GetClipMask into two + // functions: + // 1. nsSVGClipPathFrame::CreateClipMask + // Create an A8 surface with right size for painting clip-path mask. + // 2. nsSVGClipPathFrame::PaintClipMask + // Paint the content of clip-path _direct_ onto a given A8 surface. + // With this change, we can skip one extra draw call + // (DrawTarget::MaskSurface) bellow. + RefPtr clipMaskSurface = + clipPathFrame->GetClipMask(ctx, frame, cssPxToDevPxMatrix, + &clipMaskTransform, nullptr, + ToMatrix(ctx.CurrentMatrix()), &result); + + if (clipMaskSurface) { + gfxContextMatrixAutoSaveRestore matRestore(&ctx); + ctx.Multiply(ThebesMatrix(clipMaskTransform)); + CompositionOp op = maskUsage.shouldGenerateMaskLayer + ? CompositionOp::OP_IN : CompositionOp::OP_OVER; + target->MaskSurface(ColorPattern(Color(0.0, 0.0, 0.0, 1.0)), + clipMaskSurface, + Point(), + DrawOptions(1.0, op)); + } else { + // Either entire surface is clipped out, or gfx buffer allocation + // failure in nsSVGClipPathFrame::GetClipMask. + return result; + } + } + + return result; } DrawResult @@ -828,15 +880,15 @@ nsSVGIntegrationUtils::PaintMaskAndClipPath(const PaintFramesParams& aParams) SetupContextMatrix(firstFrame, aParams, offsetToBoundingBox, offsetToUserSpace, false); - Matrix clippedMaskTransform; + Matrix clipMaskTransform; RefPtr clipMaskSurface = clipPathFrame->GetClipMask(context, frame, cssPxToDevPxMatrix, - &clippedMaskTransform, maskSurface, + &clipMaskTransform, maskSurface, maskTransform, &result); if (clipMaskSurface) { maskSurface = clipMaskSurface; - maskTransform = clippedMaskTransform; + maskTransform = clipMaskTransform; } else { // Either entire surface is clipped out, or gfx buffer allocation // failure in nsSVGClipPathFrame::GetClipMask.