diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 43c994529574..5b5b9430b8a6 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -6800,7 +6800,7 @@ nsDisplaySVGEffects::PrintEffects(nsACString& aTo) aTo += "filter"; first = false; } - if (effectProperties.GetMaskFrame(&isOK)) { + if (effectProperties.GetFirstMaskFrame()) { if (!first) { aTo += ", "; } diff --git a/layout/svg/nsSVGEffects.cpp b/layout/svg/nsSVGEffects.cpp index d86d5833bc72..f52c0aeff479 100644 --- a/layout/svg/nsSVGEffects.cpp +++ b/layout/svg/nsSVGEffects.cpp @@ -364,6 +364,20 @@ nsSVGMarkerProperty::DoUpdate() frame->GetContent()->AsElement(), nsRestyleHint(0), changeHint); } +NS_IMPL_ISUPPORTS(nsSVGMaskProperty, nsISupports) + +nsSVGMaskProperty::nsSVGMaskProperty(nsIFrame* aFrame) +{ + const nsStyleSVGReset *svgReset = aFrame->StyleSVGReset(); + + for (uint32_t i = 0; i < svgReset->mMask.mImageCount; i++) { + nsSVGPaintingProperty* prop = + new nsSVGPaintingProperty(svgReset->mMask.mLayers[i].mSourceURI, aFrame, + false); + mProperties.AppendElement(prop); + } +} + bool nsSVGTextPathProperty::TargetIsValid() { @@ -487,6 +501,20 @@ GetOrCreateFilterProperty(nsIFrame *aFrame) return prop; } +static nsSVGMaskProperty* +GetOrCreateMaskProperty(nsIFrame *aFrame) +{ + FrameProperties props = aFrame->Properties(); + nsSVGMaskProperty *prop = props.Get(nsSVGEffects::MaskProperty()); + if (prop) + return prop; + + prop = new nsSVGMaskProperty(aFrame); + NS_ADDREF(prop); + props.Set(nsSVGEffects::MaskProperty(), prop); + return prop; +} + nsSVGMarkerProperty * nsSVGEffects::GetMarkerProperty(nsIURI *aURI, nsIFrame *aFrame, ObserverPropertyDescriptor aProp) @@ -553,7 +581,9 @@ nsSVGEffects::GetEffectProperties(nsIFrame *aFrame) EffectProperties result; const nsStyleSVGReset *style = aFrame->StyleSVGReset(); + result.mFilter = GetOrCreateFilterProperty(aFrame); + if (style->mClipPath.GetType() == NS_STYLE_CLIP_PATH_URL) { result.mClipPath = GetPaintingProperty(style->mClipPath.GetURL(), aFrame, ClipPathProperty()); @@ -561,12 +591,9 @@ nsSVGEffects::GetEffectProperties(nsIFrame *aFrame) result.mClipPath = nullptr; } - // FIXME: Bug 1228280. - // Before fixing bug 1228280, we support only single svg mask as before. MOZ_ASSERT(style->mMask.mImageCount > 0); - nsCOMPtr uri = style->mMask.mLayers[0].mSourceURI; - result.mMask = uri ? GetPaintingProperty(uri, aFrame, MaskProperty()) : - nullptr; + result.mMask = style->mMask.HasLayerWithImage() + ? GetOrCreateMaskProperty(aFrame) : nullptr; return result; } @@ -621,12 +648,39 @@ nsSVGEffects::EffectProperties::GetClipPathFrame(bool *aOK) } nsSVGMaskFrame * -nsSVGEffects::EffectProperties::GetMaskFrame(bool *aOK) +nsSVGEffects::EffectProperties::GetFirstMaskFrame(bool *aOK) { - if (!mMask) + if (!mMask) { return nullptr; + } + + const nsTArray>& props = mMask->GetProps(); + + if (props.IsEmpty()) { + return nullptr; + } + return static_cast - (mMask->GetReferencedFrame(nsGkAtoms::svgMaskFrame, aOK)); + (props[0]->GetReferencedFrame(nsGkAtoms::svgMaskFrame, aOK)); +} + +nsTArray +nsSVGEffects::EffectProperties::GetMaskFrames() +{ + nsTArray result; + if (!mMask) + return result; + + bool ok = false; + const nsTArray>& props = mMask->GetProps(); + for (size_t i = 0; i < props.Length(); i++) { + nsSVGMaskFrame* maskFrame = + static_cast(props[i]->GetReferencedFrame( + nsGkAtoms::svgMaskFrame, &ok)); + result.AppendElement(maskFrame); + } + + return result; } void diff --git a/layout/svg/nsSVGEffects.h b/layout/svg/nsSVGEffects.h index 9c7934e8c359..6cc83611354d 100644 --- a/layout/svg/nsSVGEffects.h +++ b/layout/svg/nsSVGEffects.h @@ -322,6 +322,24 @@ protected: virtual void DoUpdate() override; }; +class nsSVGMaskProperty final : public nsISupports +{ +public: + explicit nsSVGMaskProperty(nsIFrame* aFrame); + + // nsISupports + NS_DECL_ISUPPORTS + + const nsTArray>& GetProps() const + { + return mProperties; + } + +private: + virtual ~nsSVGMaskProperty() {} + nsTArray> mProperties; +}; + /** * A manager for one-shot nsSVGRenderingObserver tracking. * nsSVGRenderingObservers can be added or removed. They are not strongly @@ -407,7 +425,7 @@ public: NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(FilterProperty, nsSVGFilterProperty, DestroyFilterProperty) - NS_DECLARE_FRAME_PROPERTY_RELEASABLE(MaskProperty, nsISupports) + NS_DECLARE_FRAME_PROPERTY_RELEASABLE(MaskProperty, nsSVGMaskProperty) NS_DECLARE_FRAME_PROPERTY_RELEASABLE(ClipPathProperty, nsISupports) NS_DECLARE_FRAME_PROPERTY_RELEASABLE(MarkerBeginProperty, nsISupports) NS_DECLARE_FRAME_PROPERTY_RELEASABLE(MarkerMiddleProperty, nsISupports) @@ -427,7 +445,7 @@ public: struct EffectProperties { nsSVGFilterProperty* mFilter; - nsSVGPaintingProperty* mMask; + nsSVGMaskProperty* mMask; nsSVGPaintingProperty* mClipPath; /** @@ -438,12 +456,17 @@ public: */ nsSVGClipPathFrame *GetClipPathFrame(bool *aOK); /** - * @return the mask frame, or null if there is no mask frame + * @return the first mask frame, or null if there is no mask frame * @param aOK if a mask was specified and the designated element * exists but is an element of the wrong type, *aOK is set to false. * Otherwise *aOK is untouched. */ - nsSVGMaskFrame *GetMaskFrame(bool *aOK); + nsSVGMaskFrame *GetFirstMaskFrame(bool *aOK = nullptr); + + /** + * @return an array which contains all SVG mask frames. + */ + nsTArray GetMaskFrames(); bool HasValidFilter() { return mFilter && mFilter->ReferencesValidResources(); diff --git a/layout/svg/nsSVGIntegrationUtils.cpp b/layout/svg/nsSVGIntegrationUtils.cpp index dd08973c8ba6..5c115e0e6433 100644 --- a/layout/svg/nsSVGIntegrationUtils.cpp +++ b/layout/svg/nsSVGIntegrationUtils.cpp @@ -416,7 +416,7 @@ HasMaskToDraw(const nsStyleSVGReset* aSVGReset, 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.GetMaskFrame(&isOK); + nsSVGMaskFrame *svgMaskFrame = aEffectProperties.GetFirstMaskFrame(&isOK); // hasMaskToDraw is true means we have at least one drawable mask resource. // We need to apply mask only if hasMaskToDraw is true. @@ -443,10 +443,9 @@ GenerateMaskSurface(const nsSVGIntegrationUtils::PaintFramesParams& aParams, const nsStyleSVGReset *svgReset = aSC->StyleSVGReset(); MOZ_ASSERT(HasMaskToDraw(svgReset, aEffectProperties)); - bool isOK = true; - // Keep moving forward even if svgMaskFrame is nullptr or isOK is false. + // 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.GetMaskFrame(&isOK); + nsSVGMaskFrame *svgMaskFrame = aEffectProperties.GetFirstMaskFrame(); gfxContext& ctx = aParams.ctx; if (svgMaskFrame) { diff --git a/layout/svg/nsSVGUtils.cpp b/layout/svg/nsSVGUtils.cpp index 61dbca5c3329..9614fb837439 100644 --- a/layout/svg/nsSVGUtils.cpp +++ b/layout/svg/nsSVGUtils.cpp @@ -577,7 +577,7 @@ nsSVGUtils::PaintFrameWithEffects(nsIFrame *aFrame, bool complexEffects = false; nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame(&isOK); - nsSVGMaskFrame *maskFrame = effectProperties.GetMaskFrame(&isOK); + nsSVGMaskFrame *maskFrame = effectProperties.GetFirstMaskFrame(&isOK); bool isTrivialClip = clipPathFrame ? clipPathFrame->IsTrivial() : true;