Bug 1228280 - Part 4. Create nsSVGMaskProperty to carry multiple mask info;
MozReview-Commit-ID: 8NoeoA18jdZ
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -6835,17 +6835,17 @@ nsDisplaySVGEffects::PrintEffects(nsACSt
}
if (effectProperties.HasValidFilter()) {
if (!first) {
aTo += ", ";
}
aTo += "filter";
first = false;
}
- if (effectProperties.GetMaskFrame(&isOK)) {
+ if (effectProperties.GetFirstMaskFrame()) {
if (!first) {
aTo += ", ";
}
aTo += "mask";
}
aTo += ")";
}
#endif
--- a/layout/svg/nsSVGEffects.cpp
+++ b/layout/svg/nsSVGEffects.cpp
@@ -359,16 +359,30 @@ nsSVGMarkerProperty::DoUpdate()
// nsChangeHint_NeedReflow | nsChangeHint_NeedDirtyReflow here.
// XXXSDL KILL THIS!!!
nsSVGUtils::ScheduleReflowSVG(frame);
}
frame->PresContext()->RestyleManager()->PostRestyleEvent(
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()
{
Element* target = GetTarget();
return target && target->IsSVGElement(nsGkAtoms::path);
}
void
@@ -482,16 +496,30 @@ GetOrCreateFilterProperty(nsIFrame *aFra
prop = new nsSVGFilterProperty(effects->mFilters, aFrame);
if (!prop)
return nullptr;
NS_ADDREF(prop);
props.Set(nsSVGEffects::FilterProperty(), prop);
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)
{
MOZ_ASSERT(aFrame->GetType() == nsGkAtoms::svgPathGeometryFrame &&
static_cast<nsSVGPathGeometryElement*>(aFrame->GetContent())->IsMarkable(),
"Bad frame");
return static_cast<nsSVGMarkerProperty*>(
@@ -548,30 +576,29 @@ nsSVGEffects::GetPaintingPropertyForURI(
nsSVGEffects::EffectProperties
nsSVGEffects::GetEffectProperties(nsIFrame *aFrame)
{
NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame should be first continuation");
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());
} else {
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<nsIURI> uri = style->mMask.mLayers[0].mSourceURI;
- result.mMask = uri ? GetPaintingProperty(uri, aFrame, MaskProperty()) :
- nullptr;
+ result.mMask = style->mMask.HasLayerWithImage()
+ ? GetOrCreateMaskProperty(aFrame) : nullptr;
return result;
}
nsSVGPaintServerFrame *
nsSVGEffects::GetPaintServer(nsIFrame *aTargetFrame, const nsStyleSVGPaint *aPaint,
ObserverPropertyDescriptor aType)
{
@@ -616,22 +643,49 @@ nsSVGEffects::EffectProperties::GetClipP
(mClipPath->GetReferencedFrame(nsGkAtoms::svgClipPathFrame, aOK));
if (frame && aOK && *aOK) {
*aOK = frame->IsValid();
}
return frame;
}
nsSVGMaskFrame *
-nsSVGEffects::EffectProperties::GetMaskFrame(bool *aOK)
+nsSVGEffects::EffectProperties::GetFirstMaskFrame(bool *aOK)
{
+ if (!mMask) {
+ return nullptr;
+ }
+
+ const nsTArray<RefPtr<nsSVGPaintingProperty>>& props = mMask->GetProps();
+
+ if (props.IsEmpty()) {
+ return nullptr;
+ }
+
+ return static_cast<nsSVGMaskFrame *>
+ (props[0]->GetReferencedFrame(nsGkAtoms::svgMaskFrame, aOK));
+}
+
+nsTArray<nsSVGMaskFrame *>
+nsSVGEffects::EffectProperties::GetMaskFrames()
+{
+ nsTArray<nsSVGMaskFrame *> result;
if (!mMask)
- return nullptr;
- return static_cast<nsSVGMaskFrame *>
- (mMask->GetReferencedFrame(nsGkAtoms::svgMaskFrame, aOK));
+ return result;
+
+ bool ok = false;
+ const nsTArray<RefPtr<nsSVGPaintingProperty>>& props = mMask->GetProps();
+ for (size_t i = 0; i < props.Length(); i++) {
+ nsSVGMaskFrame* maskFrame =
+ static_cast<nsSVGMaskFrame *>(props[i]->GetReferencedFrame(
+ nsGkAtoms::svgMaskFrame, &ok));
+ result.AppendElement(maskFrame);
+ }
+
+ return result;
}
void
nsSVGEffects::UpdateEffects(nsIFrame *aFrame)
{
NS_ASSERTION(aFrame->GetContent()->IsElement(),
"aFrame's content should be an element");
--- a/layout/svg/nsSVGEffects.h
+++ b/layout/svg/nsSVGEffects.h
@@ -317,16 +317,34 @@ class nsSVGPaintingProperty final : publ
public:
nsSVGPaintingProperty(nsIURI *aURI, nsIFrame *aFrame, bool aReferenceImage)
: nsSVGRenderingObserverProperty(aURI, aFrame, aReferenceImage) {}
protected:
virtual void DoUpdate() override;
};
+class nsSVGMaskProperty final : public nsISupports
+{
+public:
+ explicit nsSVGMaskProperty(nsIFrame* aFrame);
+
+ // nsISupports
+ NS_DECL_ISUPPORTS
+
+ const nsTArray<RefPtr<nsSVGPaintingProperty>>& GetProps() const
+ {
+ return mProperties;
+ }
+
+private:
+ virtual ~nsSVGMaskProperty() {}
+ nsTArray<RefPtr<nsSVGPaintingProperty>> mProperties;
+};
+
/**
* A manager for one-shot nsSVGRenderingObserver tracking.
* nsSVGRenderingObservers can be added or removed. They are not strongly
* referenced so an observer must be removed before it dies.
* When InvalidateAll is called, all outstanding references get
* InvalidateViaReferencedElement()
* called on them and the list is cleared. The intent is that
* the observer will force repainting of whatever part of the document
@@ -402,17 +420,17 @@ public:
// has now become invalid.
aProp->DetachFromFrame();
aProp->Release();
}
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)
NS_DECLARE_FRAME_PROPERTY_RELEASABLE(MarkerEndProperty, nsISupports)
NS_DECLARE_FRAME_PROPERTY_RELEASABLE(FillProperty, nsISupports)
NS_DECLARE_FRAME_PROPERTY_RELEASABLE(StrokeProperty, nsISupports)
NS_DECLARE_FRAME_PROPERTY_RELEASABLE(HrefProperty, nsISupports)
NS_DECLARE_FRAME_PROPERTY_DELETABLE(BackgroundImageProperty,
@@ -422,33 +440,38 @@ public:
* Get the paint server for a aTargetFrame.
*/
static nsSVGPaintServerFrame *GetPaintServer(nsIFrame *aTargetFrame,
const nsStyleSVGPaint *aPaint,
ObserverPropertyDescriptor aProperty);
struct EffectProperties {
nsSVGFilterProperty* mFilter;
- nsSVGPaintingProperty* mMask;
+ nsSVGMaskProperty* mMask;
nsSVGPaintingProperty* mClipPath;
/**
* @return the clip-path frame, or null if there is no clip-path frame
* @param aOK if a clip-path was specified and the designated element
* exists but is an element of the wrong type, *aOK is set to false.
* Otherwise *aOK is untouched.
*/
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<nsSVGMaskFrame*> GetMaskFrames();
bool HasValidFilter() {
return mFilter && mFilter->ReferencesValidResources();
}
bool HasNoFilterOrHasValidFilter() {
return !mFilter || mFilter->ReferencesValidResources();
}
--- a/layout/svg/nsSVGIntegrationUtils.cpp
+++ b/layout/svg/nsSVGIntegrationUtils.cpp
@@ -411,17 +411,17 @@ private:
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.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.
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;
@@ -438,20 +438,19 @@ GenerateMaskSurface(const nsSVGIntegrati
float aOpacity, nsStyleContext* aSC,
nsSVGEffects::EffectProperties& aEffectProperties,
gfxMatrix aOriginMatrix, Matrix& aOutMaskTransform,
RefPtr<SourceSurface>& aOutMaskSurface)
{
const nsStyleSVGReset *svgReset = aSC->StyleSVGReset();
MOZ_ASSERT(HasMaskToDraw(svgReset, aEffectProperties) > 0);
- 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) {
gfxMatrix cssPxToDevPxMatrix =
nsSVGIntegrationUtils::GetCSSPxToDevPxMatrix(aParams.frame);
// Generate aOutMaskSurface from a SVG mask.
aOutMaskSurface = svgMaskFrame->GetMaskForMaskedFrame(&ctx,
--- a/layout/svg/nsSVGUtils.cpp
+++ b/layout/svg/nsSVGUtils.cpp
@@ -572,17 +572,17 @@ nsSVGUtils::PaintFrameWithEffects(nsIFra
if (opacity != 1.0f && CanOptimizeOpacity(aFrame))
opacity = 1.0f;
DrawTarget* drawTarget = aContext.GetDrawTarget();
bool complexEffects = false;
nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame(&isOK);
- nsSVGMaskFrame *maskFrame = effectProperties.GetMaskFrame(&isOK);
+ nsSVGMaskFrame *maskFrame = effectProperties.GetFirstMaskFrame(&isOK);
bool isTrivialClip = clipPathFrame ? clipPathFrame->IsTrivial() : true;
if (!isOK) {
// Some resource is invalid. We shouldn't paint anything.
return;
}