1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsSVGFilterFrame.h"
9 // Keep others in (case-insensitive) order:
11 #include "nsGkAtoms.h"
12 #include "nsRenderingContext.h"
13 #include "nsSVGEffects.h"
14 #include "nsSVGElement.h"
15 #include "mozilla/dom/SVGFilterElement.h"
16 #include "nsSVGFilterInstance.h"
17 #include "nsSVGIntegrationUtils.h"
18 #include "nsSVGUtils.h"
19 #include "nsContentUtils.h"
21 using namespace mozilla::dom
;
24 NS_NewSVGFilterFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
)
26 return new (aPresShell
) nsSVGFilterFrame(aContext
);
29 NS_IMPL_FRAMEARENA_HELPERS(nsSVGFilterFrame
)
31 class MOZ_STACK_CLASS
nsSVGFilterFrame::AutoFilterReferencer
34 explicit AutoFilterReferencer(nsSVGFilterFrame
*aFrame MOZ_GUARD_OBJECT_NOTIFIER_PARAM
)
37 MOZ_GUARD_OBJECT_NOTIFIER_INIT
;
38 // Reference loops should normally be detected in advance and handled, so
39 // we're not expecting to encounter them here
40 NS_ABORT_IF_FALSE(!mFrame
->mLoopFlag
, "Undetected reference loop!");
41 mFrame
->mLoopFlag
= true;
43 ~AutoFilterReferencer() {
44 mFrame
->mLoopFlag
= false;
47 nsSVGFilterFrame
*mFrame
;
48 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
52 nsSVGFilterFrame::GetEnumValue(uint32_t aIndex
, nsIContent
*aDefault
)
55 static_cast<SVGFilterElement
*>(mContent
)->mEnumAttributes
[aIndex
];
57 if (thisEnum
.IsExplicitlySet())
58 return thisEnum
.GetAnimValue();
60 AutoFilterReferencer
filterRef(this);
62 nsSVGFilterFrame
*next
= GetReferencedFilterIfNotInUse();
63 return next
? next
->GetEnumValue(aIndex
, aDefault
) :
64 static_cast<SVGFilterElement
*>(aDefault
)->
65 mEnumAttributes
[aIndex
].GetAnimValue();
69 nsSVGFilterFrame::GetLengthValue(uint32_t aIndex
, nsIContent
*aDefault
)
71 const nsSVGLength2
*thisLength
=
72 &static_cast<SVGFilterElement
*>(mContent
)->mLengthAttributes
[aIndex
];
74 if (thisLength
->IsExplicitlySet())
77 AutoFilterReferencer
filterRef(this);
79 nsSVGFilterFrame
*next
= GetReferencedFilterIfNotInUse();
80 return next
? next
->GetLengthValue(aIndex
, aDefault
) :
81 &static_cast<SVGFilterElement
*>(aDefault
)->mLengthAttributes
[aIndex
];
84 const SVGFilterElement
*
85 nsSVGFilterFrame::GetFilterContent(nsIContent
*aDefault
)
87 for (nsIContent
* child
= mContent
->GetFirstChild();
89 child
= child
->GetNextSibling()) {
90 nsRefPtr
<nsSVGFE
> primitive
;
91 CallQueryInterface(child
, (nsSVGFE
**)getter_AddRefs(primitive
));
93 return static_cast<SVGFilterElement
*>(mContent
);
97 AutoFilterReferencer
filterRef(this);
99 nsSVGFilterFrame
*next
= GetReferencedFilterIfNotInUse();
100 return next
? next
->GetFilterContent(aDefault
) :
101 static_cast<SVGFilterElement
*>(aDefault
);
105 nsSVGFilterFrame::GetReferencedFilter()
110 nsSVGPaintingProperty
*property
= static_cast<nsSVGPaintingProperty
*>
111 (Properties().Get(nsSVGEffects::HrefProperty()));
114 // Fetch our Filter element's xlink:href attribute
115 SVGFilterElement
*filter
= static_cast<SVGFilterElement
*>(mContent
);
117 filter
->mStringAttributes
[SVGFilterElement::HREF
].GetAnimValue(href
, filter
);
118 if (href
.IsEmpty()) {
120 return nullptr; // no URL
123 // Convert href to an nsIURI
124 nsCOMPtr
<nsIURI
> targetURI
;
125 nsCOMPtr
<nsIURI
> base
= mContent
->GetBaseURI();
126 nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI
), href
,
127 mContent
->GetCurrentDoc(), base
);
130 nsSVGEffects::GetPaintingProperty(targetURI
, this, nsSVGEffects::HrefProperty());
135 nsIFrame
*result
= property
->GetReferencedFrame();
139 nsIAtom
* frameType
= result
->GetType();
140 if (frameType
!= nsGkAtoms::svgFilterFrame
)
143 return static_cast<nsSVGFilterFrame
*>(result
);
147 nsSVGFilterFrame::GetReferencedFilterIfNotInUse()
149 nsSVGFilterFrame
*referenced
= GetReferencedFilter();
153 if (referenced
->mLoopFlag
) {
154 // XXXjwatt: we should really send an error to the JavaScript Console here:
155 NS_WARNING("Filter reference loop detected while inheriting attribute!");
163 nsSVGFilterFrame::AttributeChanged(int32_t aNameSpaceID
,
167 if (aNameSpaceID
== kNameSpaceID_None
&&
168 (aAttribute
== nsGkAtoms::x
||
169 aAttribute
== nsGkAtoms::y
||
170 aAttribute
== nsGkAtoms::width
||
171 aAttribute
== nsGkAtoms::height
||
172 aAttribute
== nsGkAtoms::filterUnits
||
173 aAttribute
== nsGkAtoms::primitiveUnits
)) {
174 nsSVGEffects::InvalidateDirectRenderingObservers(this);
175 } else if (aNameSpaceID
== kNameSpaceID_XLink
&&
176 aAttribute
== nsGkAtoms::href
) {
177 // Blow away our reference, if any
178 Properties().Delete(nsSVGEffects::HrefProperty());
180 // And update whoever references us
181 nsSVGEffects::InvalidateDirectRenderingObservers(this);
183 return nsSVGFilterFrameBase::AttributeChanged(aNameSpaceID
,
184 aAttribute
, aModType
);
189 nsSVGFilterFrame::Init(nsIContent
* aContent
,
190 nsContainerFrame
* aParent
,
191 nsIFrame
* aPrevInFlow
)
193 NS_ASSERTION(aContent
->IsSVG(nsGkAtoms::filter
),
194 "Content is not an SVG filter");
196 nsSVGFilterFrameBase::Init(aContent
, aParent
, aPrevInFlow
);
201 nsSVGFilterFrame::GetType() const
203 return nsGkAtoms::svgFilterFrame
;