Bug 1250490 - Part 5. Use CreateBlendTarget/BlendToTarget.
MozReview-Commit-ID: ERSXrcOW9PQ
--- a/layout/svg/nsSVGUtils.cpp
+++ b/layout/svg/nsSVGUtils.cpp
@@ -705,18 +705,46 @@ nsSVGUtils::PaintFrameWithEffects(nsIFra
nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame(&isOK);
nsSVGMaskFrame *maskFrame = effectProperties.GetFirstMaskFrame(&isOK);
if (!isOK) {
// Some resource is invalid. We shouldn't paint anything.
return DrawResult::SUCCESS;
}
// These are used if we require a temporary surface for a custom blend mode.
- RefPtr<gfxContext> target = &aContext;
+ // Clip the source context first, so that we can generate a smaller temporary
+ // surface. (Since we will clip this context in SetupContextMatrix, a pair
+ // of save/restore is needed.)
+ aContext.Save();
+ if (!(aFrame->GetStateBits() & NS_FRAME_IS_NONDISPLAY)) {
+ // aFrame has a valid visual overflow rect, so clip to it before calling
+ // PushGroup() to minimize the size of the surfaces we'll composite:
+ gfxContextMatrixAutoSaveRestore matrixAutoSaveRestore(&aContext);
+ aContext.Multiply(aTransform);
+ nsRect overflowRect = aFrame->GetVisualOverflowRectRelativeToSelf();
+ if (aFrame->IsFrameOfType(nsIFrame::eSVGGeometry) ||
+ aFrame->IsSVGText()) {
+ // Unlike containers, leaf frames do not include GetPosition() in
+ // GetCanvasTM().
+ overflowRect = overflowRect + aFrame->GetPosition();
+ }
+ aContext.Clip(NSRectToSnappedRect(overflowRect,
+ aFrame->PresContext()->AppUnitsPerDevPixel(),
+ *aContext.GetDrawTarget()));
+ }
IntPoint targetOffset;
+ RefPtr<gfxContext> target =
+ (aFrame->StyleEffects()->mMixBlendMode == NS_STYLE_BLEND_NORMAL)
+ ? RefPtr<gfxContext>(&aContext).forget()
+ : CreateBlendTarget(&aContext, targetOffset);
+ aContext.Restore();
+
+ if (!target) {
+ return DrawResult::TEMPORARY_ERROR;
+ }
/* Check if we need to do additional operations on this child's
* rendering, which necessitates rendering into another surface. */
bool shouldGenerateMask = (maskUsage.opacity != 1.0f ||
maskUsage.shouldGenerateClipMaskLayer ||
maskUsage.shouldGenerateMaskLayer ||
aFrame->StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL);
@@ -730,56 +758,16 @@ nsSVGUtils::PaintFrameWithEffects(nsIFra
maskUsage.opacity, &maskTransform);
if (!maskSurface) {
// Entire surface is clipped out.
return DrawResult::SUCCESS;
}
}
- if (!(aFrame->GetStateBits() & NS_FRAME_IS_NONDISPLAY)) {
- // aFrame has a valid visual overflow rect, so clip to it before calling
- // PushGroup() to minimize the size of the surfaces we'll composite:
- gfxContextMatrixAutoSaveRestore matrixAutoSaveRestore(&aContext);
- aContext.Multiply(aTransform);
- nsRect overflowRect = aFrame->GetVisualOverflowRectRelativeToSelf();
- if (aFrame->IsFrameOfType(nsIFrame::eSVGGeometry) ||
- aFrame->IsSVGText()) {
- // Unlike containers, leaf frames do not include GetPosition() in
- // GetCanvasTM().
- overflowRect = overflowRect + aFrame->GetPosition();
- }
- aContext.Clip(NSRectToSnappedRect(overflowRect,
- aFrame->PresContext()->AppUnitsPerDevPixel(),
- *aContext.GetDrawTarget()));
- }
-
- if (aFrame->StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
- // Create a temporary context to draw to so we can blend it back with
- // another operator.
- gfxRect clipRect;
- {
- gfxContextMatrixAutoSaveRestore matRestore(&aContext);
-
- aContext.SetMatrix(gfxMatrix());
- clipRect = aContext.GetClipExtents();
- }
-
- IntRect drawRect = RoundedOut(ToRect(clipRect));
-
- RefPtr<DrawTarget> targetDT = aContext.GetDrawTarget()->CreateSimilarDrawTarget(drawRect.Size(), SurfaceFormat::B8G8R8A8);
- target = gfxContext::CreateOrNull(targetDT);
- if (!target) {
- gfxDevCrash(LogReason::InvalidContext) << "SVGPaintWithEffects context problem " << gfx::hexa(targetDT);
- return DrawResult::TEMPORARY_ERROR;
- }
- target->SetMatrix(aContext.CurrentMatrix() * gfxMatrix::Translation(-drawRect.TopLeft()));
- targetOffset = drawRect.TopLeft();
- }
-
if (maskUsage.shouldGenerateClipMaskLayer) {
Matrix clippedMaskTransform;
RefPtr<SourceSurface> clipMaskSurface =
clipPathFrame->GetClipMask(aContext, aFrame, aTransform,
&clippedMaskTransform, maskSurface,
maskTransform);
if (clipMaskSurface) {
@@ -842,24 +830,18 @@ nsSVGUtils::PaintFrameWithEffects(nsIFra
aContext.PopClip();
}
if (shouldGenerateMask) {
target->PopGroupAndBlend();
}
if (aFrame->StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
- RefPtr<DrawTarget> targetDT = target->GetDrawTarget();
- target = nullptr;
- RefPtr<SourceSurface> targetSurf = targetDT->Snapshot();
-
- aContext.SetMatrix(gfxMatrix()); // This will be restored right after.
- RefPtr<gfxPattern> pattern = new gfxPattern(targetSurf, Matrix::Translation(targetOffset.x, targetOffset.y));
- aContext.SetPattern(pattern);
- aContext.Paint();
+ MOZ_ASSERT(target != &aContext);
+ BlendToTarget(aFrame, &aContext, target, targetOffset);
}
return result;
}
bool
nsSVGUtils::HitTestClip(nsIFrame *aFrame, const gfxPoint &aPoint)
{