1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/dom/SVGImageElement.h"
9 #include "mozilla/ArrayUtils.h"
10 #include "mozilla/gfx/2D.h"
13 #include "nsNetUtil.h"
14 #include "imgINotificationObserver.h"
15 #include "mozilla/dom/Document.h"
16 #include "mozilla/dom/SVGImageElementBinding.h"
17 #include "mozilla/dom/SVGLengthBinding.h"
18 #include "mozilla/dom/UserActivation.h"
19 #include "nsContentUtils.h"
20 #include "SVGGeometryProperty.h"
22 NS_IMPL_NS_NEW_SVG_ELEMENT(Image
)
24 using namespace mozilla::gfx
;
26 namespace mozilla::dom
{
28 JSObject
* SVGImageElement::WrapNode(JSContext
* aCx
,
29 JS::Handle
<JSObject
*> aGivenProto
) {
30 return SVGImageElement_Binding::Wrap(aCx
, this, aGivenProto
);
33 SVGElement::LengthInfo
SVGImageElement::sLengthInfo
[4] = {
34 {nsGkAtoms::x
, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER
,
36 {nsGkAtoms::y
, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER
,
38 {nsGkAtoms::width
, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER
,
40 {nsGkAtoms::height
, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER
,
44 SVGElement::StringInfo
SVGImageElement::sStringInfo
[2] = {
45 {nsGkAtoms::href
, kNameSpaceID_None
, true},
46 {nsGkAtoms::href
, kNameSpaceID_XLink
, true}};
48 //----------------------------------------------------------------------
49 // nsISupports methods
51 NS_IMPL_ISUPPORTS_INHERITED(SVGImageElement
, SVGImageElementBase
,
52 imgINotificationObserver
, nsIImageLoadingContent
)
54 //----------------------------------------------------------------------
57 namespace SVGT
= SVGGeometryProperty::Tags
;
59 SVGImageElement::SVGImageElement(
60 already_AddRefed
<mozilla::dom::NodeInfo
>&& aNodeInfo
)
61 : SVGImageElementBase(std::move(aNodeInfo
)) {
62 // We start out broken
63 AddStatesSilently(ElementState::BROKEN
);
66 SVGImageElement::~SVGImageElement() { nsImageLoadingContent::Destroy(); }
68 nsCSSPropertyID
SVGImageElement::GetCSSPropertyIdForAttrEnum(
72 return eCSSProperty_x
;
74 return eCSSProperty_y
;
76 return eCSSProperty_width
;
78 return eCSSProperty_height
;
80 MOZ_ASSERT_UNREACHABLE("Unknown attr enum");
81 return eCSSProperty_UNKNOWN
;
84 //----------------------------------------------------------------------
87 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGImageElement
)
89 //----------------------------------------------------------------------
91 already_AddRefed
<DOMSVGAnimatedLength
> SVGImageElement::X() {
92 return mLengthAttributes
[ATTR_X
].ToDOMAnimatedLength(this);
95 already_AddRefed
<DOMSVGAnimatedLength
> SVGImageElement::Y() {
96 return mLengthAttributes
[ATTR_Y
].ToDOMAnimatedLength(this);
99 already_AddRefed
<DOMSVGAnimatedLength
> SVGImageElement::Width() {
100 return mLengthAttributes
[ATTR_WIDTH
].ToDOMAnimatedLength(this);
103 already_AddRefed
<DOMSVGAnimatedLength
> SVGImageElement::Height() {
104 return mLengthAttributes
[ATTR_HEIGHT
].ToDOMAnimatedLength(this);
107 already_AddRefed
<DOMSVGAnimatedPreserveAspectRatio
>
108 SVGImageElement::PreserveAspectRatio() {
109 return mPreserveAspectRatio
.ToDOMAnimatedPreserveAspectRatio(this);
112 already_AddRefed
<DOMSVGAnimatedString
> SVGImageElement::Href() {
113 return mStringAttributes
[HREF
].IsExplicitlySet()
114 ? mStringAttributes
[HREF
].ToDOMAnimatedString(this)
115 : mStringAttributes
[XLINK_HREF
].ToDOMAnimatedString(this);
118 void SVGImageElement::GetDecoding(nsAString
& aValue
) {
119 GetEnumAttr(nsGkAtoms::decoding
, kDecodingTableDefault
->tag
, aValue
);
122 already_AddRefed
<Promise
> SVGImageElement::Decode(ErrorResult
& aRv
) {
123 return nsImageLoadingContent::QueueDecodeAsync(aRv
);
126 //----------------------------------------------------------------------
128 nsresult
SVGImageElement::LoadSVGImage(bool aForce
, bool aNotify
) {
129 // resolve href attribute
130 nsIURI
* baseURI
= GetBaseURI();
133 if (mStringAttributes
[HREF
].IsExplicitlySet()) {
134 mStringAttributes
[HREF
].GetAnimValue(href
, this);
136 mStringAttributes
[XLINK_HREF
].GetAnimValue(href
, this);
138 href
.Trim(" \t\n\r");
140 if (baseURI
&& !href
.IsEmpty()) NS_MakeAbsoluteURI(href
, href
, baseURI
);
142 // Mark channel as urgent-start before load image if the image load is
143 // initaiated by a user interaction.
144 mUseUrgentStartForChannel
= UserActivation::IsHandlingUserInput();
146 return LoadImage(href
, aForce
, aNotify
, eImageLoadType_Normal
);
149 bool SVGImageElement::ShouldLoadImage() const {
150 return LoadingEnabled() && OwnerDoc()->ShouldLoadImages();
153 Rect
SVGImageElement::GeometryBounds(const Matrix
& aToBoundsSpace
) {
157 SVGGeometryProperty::ResolveAll
<SVGT::X
, SVGT::Y
, SVGT::Width
,
158 SVGT::Height
>(this, &rect
.x
, &rect
.y
,
159 &rect
.width
, &rect
.height
);
160 MOZ_ASSERT(ok
, "SVGGeometryProperty::ResolveAll failed");
162 if (rect
.IsEmpty()) {
163 // Rendering of the element disabled
164 rect
.SetEmpty(); // Make sure width/height are zero and not negative
167 return aToBoundsSpace
.TransformBounds(rect
);
170 //----------------------------------------------------------------------
171 // EventTarget methods:
173 void SVGImageElement::AsyncEventRunning(AsyncEventDispatcher
* aEvent
) {
174 nsImageLoadingContent::AsyncEventRunning(aEvent
);
177 //----------------------------------------------------------------------
178 // nsImageLoadingContent methods:
180 CORSMode
SVGImageElement::GetCORSMode() {
181 return AttrValueToCORSMode(GetParsedAttr(nsGkAtoms::crossorigin
));
184 //----------------------------------------------------------------------
185 // nsIContent methods:
187 bool SVGImageElement::ParseAttribute(int32_t aNamespaceID
, nsAtom
* aAttribute
,
188 const nsAString
& aValue
,
189 nsIPrincipal
* aMaybeScriptedPrincipal
,
190 nsAttrValue
& aResult
) {
191 if (aNamespaceID
== kNameSpaceID_None
) {
192 if (aAttribute
== nsGkAtoms::crossorigin
) {
193 ParseCORSValue(aValue
, aResult
);
196 if (aAttribute
== nsGkAtoms::decoding
) {
197 return aResult
.ParseEnumValue(aValue
, kDecodingTable
, false,
198 kDecodingTableDefault
);
202 return SVGImageElementBase::ParseAttribute(aNamespaceID
, aAttribute
, aValue
,
203 aMaybeScriptedPrincipal
, aResult
);
206 void SVGImageElement::AfterSetAttr(int32_t aNamespaceID
, nsAtom
* aName
,
207 const nsAttrValue
* aValue
,
208 const nsAttrValue
* aOldValue
,
209 nsIPrincipal
* aSubjectPrincipal
,
211 if (aName
== nsGkAtoms::href
&& (aNamespaceID
== kNameSpaceID_None
||
212 aNamespaceID
== kNameSpaceID_XLink
)) {
214 if (ShouldLoadImage()) {
215 LoadSVGImage(true, aNotify
);
218 CancelImageRequests(aNotify
);
220 } else if (aNamespaceID
== kNameSpaceID_None
) {
221 if (aName
== nsGkAtoms::decoding
) {
222 // Request sync or async image decoding.
224 aValue
&& static_cast<ImageDecodingType
>(aValue
->GetEnumValue()) ==
225 ImageDecodingType::Sync
);
226 } else if (aName
== nsGkAtoms::crossorigin
) {
227 if (aNotify
&& GetCORSMode() != AttrValueToCORSMode(aOldValue
) &&
229 ForceReload(aNotify
, IgnoreErrors());
234 return SVGImageElementBase::AfterSetAttr(
235 aNamespaceID
, aName
, aValue
, aOldValue
, aSubjectPrincipal
, aNotify
);
238 void SVGImageElement::MaybeLoadSVGImage() {
239 if ((mStringAttributes
[HREF
].IsExplicitlySet() ||
240 mStringAttributes
[XLINK_HREF
].IsExplicitlySet()) &&
241 (NS_FAILED(LoadSVGImage(false, true)) || !LoadingEnabled())) {
242 CancelImageRequests(true);
246 nsresult
SVGImageElement::BindToTree(BindContext
& aContext
, nsINode
& aParent
) {
247 nsresult rv
= SVGImageElementBase::BindToTree(aContext
, aParent
);
248 NS_ENSURE_SUCCESS(rv
, rv
);
250 nsImageLoadingContent::BindToTree(aContext
, aParent
);
252 if ((mStringAttributes
[HREF
].IsExplicitlySet() ||
253 mStringAttributes
[XLINK_HREF
].IsExplicitlySet()) &&
255 nsContentUtils::AddScriptRunner(
256 NewRunnableMethod("dom::SVGImageElement::MaybeLoadSVGImage", this,
257 &SVGImageElement::MaybeLoadSVGImage
));
263 void SVGImageElement::UnbindFromTree(bool aNullParent
) {
264 nsImageLoadingContent::UnbindFromTree(aNullParent
);
265 SVGImageElementBase::UnbindFromTree(aNullParent
);
268 void SVGImageElement::DestroyContent() {
269 nsImageLoadingContent::Destroy();
270 SVGImageElementBase::DestroyContent();
274 SVGImageElement::IsAttributeMapped(const nsAtom
* name
) const {
275 return IsInLengthInfo(name
, sLengthInfo
) ||
276 SVGImageElementBase::IsAttributeMapped(name
);
279 //----------------------------------------------------------------------
280 // SVGElement methods
283 bool SVGImageElement::HasValidDimensions() const {
286 if (SVGGeometryProperty::ResolveAll
<SVGT::Width
, SVGT::Height
>(this, &width
,
288 return width
> 0 && height
> 0;
290 // This function might be called for an element in display:none subtree
291 // (e.g. SMIL animateMotion), we fall back to use SVG attributes.
292 return (!mLengthAttributes
[ATTR_WIDTH
].IsExplicitlySet() ||
293 mLengthAttributes
[ATTR_WIDTH
].GetAnimValInSpecifiedUnits() > 0) &&
294 (!mLengthAttributes
[ATTR_HEIGHT
].IsExplicitlySet() ||
295 mLengthAttributes
[ATTR_HEIGHT
].GetAnimValInSpecifiedUnits() > 0);
298 SVGElement::LengthAttributesInfo
SVGImageElement::GetLengthInfo() {
299 return LengthAttributesInfo(mLengthAttributes
, sLengthInfo
,
300 ArrayLength(sLengthInfo
));
303 SVGAnimatedPreserveAspectRatio
*
304 SVGImageElement::GetAnimatedPreserveAspectRatio() {
305 return &mPreserveAspectRatio
;
308 SVGElement::StringAttributesInfo
SVGImageElement::GetStringInfo() {
309 return StringAttributesInfo(mStringAttributes
, sStringInfo
,
310 ArrayLength(sStringInfo
));
313 } // namespace mozilla::dom