diff --git a/layout/svg/nsSVGUtils.cpp b/layout/svg/nsSVGUtils.cpp index b1f5c8a5310e..2118d7fec5de 100644 --- a/layout/svg/nsSVGUtils.cpp +++ b/layout/svg/nsSVGUtils.cpp @@ -486,6 +486,84 @@ public: } }; +float +nsSVGUtils::ComputeOpacity(nsIFrame* aFrame, bool aHandleOpacity) +{ + float opacity = aFrame->StyleEffects()->mOpacity; + + if (opacity != 1.0f && + (nsSVGUtils::CanOptimizeOpacity(aFrame) || !aHandleOpacity)) { + return 1.0f; + } + + return opacity; +} + +void +nsSVGUtils::DetermineMaskUsage(nsIFrame* aFrame, bool aHandleOpacity, + MaskUsage& aUsage) +{ + aUsage.opacity = ComputeOpacity(aFrame, aHandleOpacity); + + nsIFrame* firstFrame = + nsLayoutUtils::FirstContinuationOrIBSplitSibling(aFrame); + + nsSVGEffects::EffectProperties effectProperties = + nsSVGEffects::GetEffectProperties(firstFrame); + const nsStyleSVGReset *svgReset = firstFrame->StyleSVGReset(); + + nsTArray maskFrames = effectProperties.GetMaskFrames(); + +#ifdef MOZ_ENABLE_MASK_AS_SHORTHAND + // For a HTML doc: + // According to css-masking spec, always create a mask surface when we + // have any item in maskFrame even if all of those items are + // non-resolvable or , we still need to create a + // transparent black mask layer under this condition. + // For a SVG doc: + // SVG 1.1 say that if we fail to resolve a mask, we should draw the + // object unmasked. + aUsage.shouldGenerateMaskLayer = + (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) + ? maskFrames.Length() == 1 && maskFrames[0] + : maskFrames.Length() > 0; +#else + // Since we do not support image mask so far, we should treat any + // unresolvable mask as no mask. Otherwise, any object with a valid image + // mask, e.g. url("xxx.png"), will become invisible just because we can not + // handle image mask correctly. (See bug 1294171) + aUsage.shouldGenerateMaskLayer = maskFrames.Length() == 1 && maskFrames[0]; +#endif + + bool isOK = effectProperties.HasNoFilterOrHasValidFilter(); + nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame(&isOK); + MOZ_ASSERT_IF(clipPathFrame, + svgReset->mClipPath.GetType() == StyleShapeSourceType::URL); + + switch (svgReset->mClipPath.GetType()) { + case StyleShapeSourceType::URL: + if (clipPathFrame) { + if (clipPathFrame->IsTrivial()) { + aUsage.shouldApplyClipPath = true; + } else { + aUsage.shouldGenerateClipMaskLayer = true; + } + } + break; + case StyleShapeSourceType::Shape: + case StyleShapeSourceType::Box: + aUsage.shouldApplyBasicShape = true; + break; + case StyleShapeSourceType::None: + MOZ_ASSERT(!aUsage.shouldGenerateClipMaskLayer && + !aUsage.shouldApplyClipPath && !aUsage.shouldApplyBasicShape); + break; + default: + MOZ_ASSERT_UNREACHABLE("Unsupported clip-path type."); + break; + } +} + DrawResult nsSVGUtils::PaintFrameWithEffects(nsIFrame *aFrame, gfxContext& aContext, @@ -566,7 +644,7 @@ nsSVGUtils::PaintFrameWithEffects(nsIFrame *aFrame, * * + Use cairo's clipPath when representable natively (single object * clip region). - * + *f * + Merge opacity and masking if both used together. */ diff --git a/layout/svg/nsSVGUtils.h b/layout/svg/nsSVGUtils.h index 9a8c35e192a9..edfc43bee7dc 100644 --- a/layout/svg/nsSVGUtils.h +++ b/layout/svg/nsSVGUtils.h @@ -576,6 +576,25 @@ public: ToCanvasBounds(const gfxRect &aUserspaceRect, const gfxMatrix &aToCanvas, const nsPresContext *presContext); + + struct MaskUsage { + bool shouldGenerateMaskLayer; + bool shouldGenerateClipMaskLayer; + bool shouldApplyClipPath; + bool shouldApplyBasicShape; + float opacity; + + MaskUsage() + : shouldGenerateMaskLayer(false), shouldGenerateClipMaskLayer(false), + shouldApplyClipPath(false), shouldApplyBasicShape(false), opacity(0.0) + { } + }; + + static void + DetermineMaskUsage(nsIFrame* aFrame, bool aHandleOpacity, MaskUsage& aUsage); + + static float + ComputeOpacity(nsIFrame* aFrame, bool aHandleOpacity); }; #endif