Bug 1322286 - Part 1. Check maskFrame pointer value before dereference.
MozReview-Commit-ID: oXVxT8h1vz
--- a/layout/svg/nsSVGUtils.cpp
+++ b/layout/svg/nsSVGUtils.cpp
@@ -760,34 +760,42 @@ nsSVGUtils::PaintFrameWithEffects(nsIFra
DrawResult result = DrawResult::SUCCESS;
/* 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);
+ bool shouldPushMask = false;
if (shouldGenerateMask) {
Matrix maskTransform;
RefPtr<SourceSurface> maskSurface;
- if (maskUsage.shouldGenerateMaskLayer) {
+ // maskFrame can be nullptr even if maskUsage.shouldGenerateMaskLayer is
+ // true. That happens when a user gives an unresolvable mask-id, such as
+ // mask:url()
+ // mask:url(#id-which-is-not-exist)
+ // Since we only uses nsSVGUtils with SVG elements, not like mask on an
+ // HTML element, we should treat an unresolvable mask as no-mask here.
+ if (maskUsage.shouldGenerateMaskLayer && maskFrame) {
uint8_t maskMode =
aFrame->StyleSVGReset()->mMask.mLayers[0].mMaskMode;
nsSVGMaskFrame::MaskParams params(&aContext, aFrame, aTransform,
maskUsage.opacity, &maskTransform,
maskMode);
Tie(result, maskSurface) = maskFrame->GetMaskForMaskedFrame(params);
if (!maskSurface) {
// Either entire surface is clipped out, or gfx buffer allocation
// failure in nsSVGMaskFrame::GetMaskForMaskedFrame.
return result;
}
+ shouldPushMask = true;
}
if (maskUsage.shouldGenerateClipMaskLayer) {
Matrix clippedMaskTransform;
DrawResult clipMaskResult;
RefPtr<SourceSurface> clipMaskSurface;
Tie(clipMaskResult, clipMaskSurface) =
clipPathFrame->GetClipMask(aContext, aFrame, aTransform,
@@ -797,23 +805,31 @@ nsSVGUtils::PaintFrameWithEffects(nsIFra
if (clipMaskSurface) {
maskSurface = clipMaskSurface;
maskTransform = clippedMaskTransform;
} else {
// Either entire surface is clipped out, or gfx buffer allocation
// failure in nsSVGClipPathFrame::GetClipMask.
return result;
}
+ shouldPushMask = true;
+ }
+
+ if (!maskUsage.shouldGenerateClipMaskLayer &&
+ !maskUsage.shouldGenerateMaskLayer) {
+ shouldPushMask = true;
}
// SVG mask multiply opacity into maskSurface already, so we do not bother
// to apply opacity again.
- float opacity = maskFrame ? 1.0 : maskUsage.opacity;
- target->PushGroupForBlendBack(gfxContentType::COLOR_ALPHA, opacity,
- maskSurface, maskTransform);
+ if (shouldPushMask) {
+ target->PushGroupForBlendBack(gfxContentType::COLOR_ALPHA,
+ maskFrame ? 1.0 : maskUsage.opacity,
+ maskSurface, maskTransform);
+ }
}
/* If this frame has only a trivial clipPath, set up cairo's clipping now so
* we can just do normal painting and get it clipped appropriately.
*/
if (maskUsage.shouldApplyClipPath || maskUsage.shouldApplyBasicShape) {
if (maskUsage.shouldApplyClipPath) {
clipPathFrame->ApplyClipPath(aContext, aFrame, aTransform);
@@ -851,17 +867,17 @@ nsSVGUtils::PaintFrameWithEffects(nsIFra
} else {
result = svgChildFrame->PaintSVG(*target, aTransform, aDirtyRect);
}
if (maskUsage.shouldApplyClipPath || maskUsage.shouldApplyBasicShape) {
aContext.PopClip();
}
- if (shouldGenerateMask) {
+ if (shouldPushMask) {
target->PopGroupAndBlend();
}
if (blender.ShouldCreateDrawTargetForBlend()) {
MOZ_ASSERT(target != &aContext);
blender.BlendToTarget();
}