mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 23:31:56 +00:00
Bug 1228280 - Part 5. Paint multiple SVG and image masks;
MozReview-Commit-ID: FOgcnR9cYlH
This commit is contained in:
parent
936ab8c243
commit
27969c0e19
@ -413,100 +413,108 @@ static bool
|
||||
HasMaskToDraw(const nsStyleSVGReset* aSVGReset,
|
||||
nsSVGEffects::EffectProperties& aEffectProperties)
|
||||
{
|
||||
bool isOK = true;
|
||||
// Keep moving forward even if svgMaskFrame is nullptr or isOK is false.
|
||||
// This source is not a svg mask, but it still can be a correct mask image.
|
||||
nsSVGMaskFrame *svgMaskFrame = aEffectProperties.GetFirstMaskFrame(&isOK);
|
||||
nsTArray<nsSVGMaskFrame*> svgMaskFrames = aEffectProperties.GetMaskFrames();
|
||||
for (int i = svgMaskFrames.Length() - 1; i >= 0 ; i--) {
|
||||
nsSVGMaskFrame *maskFrame = svgMaskFrames[i];
|
||||
|
||||
// hasMaskToDraw is true means we have at least one drawable mask resource.
|
||||
// We need to apply mask only if hasMaskToDraw is true.
|
||||
bool hasMaskToDraw = (svgMaskFrame != nullptr);
|
||||
if (!hasMaskToDraw) {
|
||||
NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, aSVGReset->mMask) {
|
||||
if (!aSVGReset->mMask.mLayers[i].mImage.IsEmpty()) {
|
||||
hasMaskToDraw = true;
|
||||
break;
|
||||
}
|
||||
// We found a SVG mask or an image mask.
|
||||
if (maskFrame || !aSVGReset->mMask.mLayers[i].mImage.IsEmpty()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return hasMaskToDraw;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
GenerateMaskSurface(const nsSVGIntegrationUtils::PaintFramesParams& aParams,
|
||||
float aOpacity, nsStyleContext* aSC,
|
||||
nsSVGEffects::EffectProperties& aEffectProperties,
|
||||
gfxMatrix aOriginMatrix, Matrix& aOutMaskTransform,
|
||||
const gfxPoint& aOffest, Matrix& aOutMaskTransform,
|
||||
RefPtr<SourceSurface>& aOutMaskSurface)
|
||||
{
|
||||
const nsStyleSVGReset *svgReset = aSC->StyleSVGReset();
|
||||
MOZ_ASSERT(HasMaskToDraw(svgReset, aEffectProperties));
|
||||
|
||||
// Keep moving forward even if svgMaskFrame is nullptr.
|
||||
// This source is not a svg mask, but it still can be a correct mask image.
|
||||
nsSVGMaskFrame *svgMaskFrame = aEffectProperties.GetFirstMaskFrame();
|
||||
nsTArray<nsSVGMaskFrame *> svgMaskFrames = aEffectProperties.GetMaskFrames();
|
||||
MOZ_ASSERT(svgMaskFrames.Length() == svgReset->mMask.mImageCount);
|
||||
|
||||
gfxMatrix cssPxToDevPxMatrix =
|
||||
nsSVGIntegrationUtils::GetCSSPxToDevPxMatrix(aParams.frame);
|
||||
|
||||
gfxContext& ctx = aParams.ctx;
|
||||
ctx.Save();
|
||||
ctx.SetMatrix(gfxMatrix());
|
||||
gfxRect clipExtents = ctx.GetClipExtents();
|
||||
IntRect maskSurfaceRect = RoundedOut(ToRect(clipExtents));
|
||||
ctx.Restore();
|
||||
|
||||
if (svgMaskFrame) {
|
||||
gfxMatrix cssPxToDevPxMatrix =
|
||||
nsSVGIntegrationUtils::GetCSSPxToDevPxMatrix(aParams.frame);
|
||||
// Mask composition result on CoreGraphic::A8 surface is not correct
|
||||
// when mask-mode is not add(source over). Switch to skia when CG backend
|
||||
// detected.
|
||||
RefPtr<DrawTarget> maskDT =
|
||||
(ctx.GetDrawTarget()->GetBackendType() == BackendType::COREGRAPHICS)
|
||||
? Factory::CreateDrawTarget(BackendType::SKIA, maskSurfaceRect.Size(),
|
||||
SurfaceFormat::A8)
|
||||
: ctx.GetDrawTarget()->CreateSimilarDrawTarget(maskSurfaceRect.Size(),
|
||||
SurfaceFormat::A8);
|
||||
RefPtr<gfxContext> maskContext = gfxContext::ForDrawTarget(maskDT);
|
||||
|
||||
// Generate aOutMaskSurface from a SVG mask.
|
||||
aOutMaskSurface = svgMaskFrame->GetMaskForMaskedFrame(&ctx,
|
||||
aParams.frame,
|
||||
cssPxToDevPxMatrix,
|
||||
aOpacity,
|
||||
&aOutMaskTransform,
|
||||
svgReset->mMask.mLayers[0].mMaskMode);
|
||||
} else {
|
||||
// Create maskSuface.
|
||||
gfxRect clipRect = ctx.GetClipExtents();
|
||||
{
|
||||
gfxContextMatrixAutoSaveRestore matRestore(&ctx);
|
||||
// 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);
|
||||
|
||||
ctx.SetMatrix(gfxMatrix());
|
||||
clipRect = ctx.GetClipExtents();
|
||||
// Multiple SVG masks interleave with image mask. Paint each layer onto maskDT
|
||||
// one at a time.
|
||||
for (int i = svgMaskFrames.Length() - 1; i >= 0 ; i--) {
|
||||
nsSVGMaskFrame *maskFrame = svgMaskFrames[i];
|
||||
|
||||
// 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, 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->DrawSurface(svgMask, drawRect, drawRect);
|
||||
}
|
||||
} else {
|
||||
gfxContextMatrixAutoSaveRestore matRestore(maskContext);
|
||||
|
||||
maskContext->Multiply(gfxMatrix::Translation(-aOffest));
|
||||
CompositionOp compositionOp =
|
||||
nsCSSRendering::GetGFXCompositeMode(svgReset->mMask.mLayers[i].mComposite);
|
||||
nsRenderingContext rc(maskContext);
|
||||
nsCSSRendering::PaintBGParams params =
|
||||
nsCSSRendering::PaintBGParams::ForSingleLayer(*aParams.frame->PresContext(),
|
||||
rc, aParams.dirtyRect,
|
||||
aParams.borderArea,
|
||||
aParams.frame,
|
||||
aParams.builder->GetBackgroundPaintFlags() |
|
||||
nsCSSRendering::PAINTBG_MASK_IMAGE,
|
||||
i, compositionOp);
|
||||
|
||||
// FIXME We should use the return value, see bug 1258510.
|
||||
Unused << nsCSSRendering::PaintBackgroundWithSC(params, aSC,
|
||||
*aParams.frame->StyleBorder());
|
||||
}
|
||||
IntRect drawRect = RoundedOut(ToRect(clipRect));
|
||||
|
||||
// Mask composition result on CoreGraphic::A8 surface is not correct
|
||||
// when mask-mode is not add(source over). Switch to skia when CG backend
|
||||
// detected.
|
||||
RefPtr<DrawTarget> targetDT =
|
||||
(ctx.GetDrawTarget()->GetBackendType() == BackendType::COREGRAPHICS) ?
|
||||
Factory::CreateDrawTarget(BackendType::SKIA, drawRect.Size(),
|
||||
SurfaceFormat::A8) :
|
||||
ctx.GetDrawTarget()->CreateSimilarDrawTarget(drawRect.Size(),
|
||||
SurfaceFormat::A8);
|
||||
|
||||
if (!targetDT || !targetDT->IsValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<gfxContext> target = gfxContext::ForDrawTarget(targetDT);
|
||||
MOZ_ASSERT(target); // alrady checked the draw target above
|
||||
target->SetMatrix(aOriginMatrix * gfxMatrix::Translation(-drawRect.TopLeft()));
|
||||
|
||||
// Compose all mask-images onto aOutMaskSurface.
|
||||
nsRenderingContext rc(target);
|
||||
nsCSSRendering::PaintBGParams params =
|
||||
nsCSSRendering::PaintBGParams::ForAllLayers(*aParams.frame->PresContext(),
|
||||
rc, aParams.dirtyRect,
|
||||
aParams.borderArea,
|
||||
aParams.frame,
|
||||
aParams.builder->GetBackgroundPaintFlags() |
|
||||
nsCSSRendering::PAINTBG_MASK_IMAGE);
|
||||
// FIXME We should use the return value, see bug 1258510.
|
||||
Unused << nsCSSRendering::PaintBackgroundWithSC(params, aSC,
|
||||
*aParams.frame->StyleBorder());
|
||||
aOutMaskSurface = targetDT->Snapshot();
|
||||
|
||||
// Compute mask transform.
|
||||
Matrix mat = ToMatrix(ctx.CurrentMatrix());
|
||||
mat.Invert();
|
||||
aOutMaskTransform = Matrix::Translation(drawRect.x, drawRect.y) * mat;
|
||||
}
|
||||
|
||||
aOutMaskTransform = ToMatrix(maskSurfaceMatrix);
|
||||
if (!aOutMaskTransform.Invert()) {
|
||||
return;
|
||||
}
|
||||
|
||||
aOutMaskSurface = maskDT->Snapshot();
|
||||
}
|
||||
|
||||
void
|
||||
@ -632,7 +640,7 @@ nsSVGIntegrationUtils::PaintFramesWithEffects(const PaintFramesParams& aParams)
|
||||
|
||||
if (hasMaskToDraw) {
|
||||
GenerateMaskSurface(aParams, opacity, firstFrame->StyleContext(),
|
||||
effectProperties, matrixAutoSaveRestore.Matrix(),
|
||||
effectProperties, devPixelOffsetToUserSpace,
|
||||
maskTransform, maskSurface);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user