no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / dom / svg / SVGImageElement.cpp
blob014303c912cbee934f601fbb6cc4c9b5cc559c98
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"
11 #include "nsCOMPtr.h"
12 #include "nsIURI.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,
35 SVGContentUtils::X},
36 {nsGkAtoms::y, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER,
37 SVGContentUtils::Y},
38 {nsGkAtoms::width, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER,
39 SVGContentUtils::X},
40 {nsGkAtoms::height, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER,
41 SVGContentUtils::Y},
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 //----------------------------------------------------------------------
55 // Implementation
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(
69 uint8_t aAttrEnum) {
70 switch (aAttrEnum) {
71 case ATTR_X:
72 return eCSSProperty_x;
73 case ATTR_Y:
74 return eCSSProperty_y;
75 case ATTR_WIDTH:
76 return eCSSProperty_width;
77 case ATTR_HEIGHT:
78 return eCSSProperty_height;
79 default:
80 MOZ_ASSERT_UNREACHABLE("Unknown attr enum");
81 return eCSSProperty_UNKNOWN;
84 //----------------------------------------------------------------------
85 // nsINode methods
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();
132 nsAutoString href;
133 if (mStringAttributes[HREF].IsExplicitlySet()) {
134 mStringAttributes[HREF].GetAnimValue(href, this);
135 } else {
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) {
154 Rect rect;
156 DebugOnly<bool> ok =
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);
194 return true;
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,
210 bool aNotify) {
211 if (aName == nsGkAtoms::href && (aNamespaceID == kNameSpaceID_None ||
212 aNamespaceID == kNameSpaceID_XLink)) {
213 if (aValue) {
214 if (ShouldLoadImage()) {
215 LoadSVGImage(true, aNotify);
217 } else {
218 CancelImageRequests(aNotify);
220 } else if (aNamespaceID == kNameSpaceID_None) {
221 if (aName == nsGkAtoms::decoding) {
222 // Request sync or async image decoding.
223 SetSyncDecodingHint(
224 aValue && static_cast<ImageDecodingType>(aValue->GetEnumValue()) ==
225 ImageDecodingType::Sync);
226 } else if (aName == nsGkAtoms::crossorigin) {
227 if (aNotify && GetCORSMode() != AttrValueToCORSMode(aOldValue) &&
228 ShouldLoadImage()) {
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()) &&
254 ShouldLoadImage()) {
255 nsContentUtils::AddScriptRunner(
256 NewRunnableMethod("dom::SVGImageElement::MaybeLoadSVGImage", this,
257 &SVGImageElement::MaybeLoadSVGImage));
260 return rv;
263 void SVGImageElement::UnbindFromTree(bool aNullParent) {
264 nsImageLoadingContent::UnbindFromTree(aNullParent);
265 SVGImageElementBase::UnbindFromTree(aNullParent);
268 void SVGImageElement::DestroyContent() {
269 nsImageLoadingContent::Destroy();
270 SVGImageElementBase::DestroyContent();
273 NS_IMETHODIMP_(bool)
274 SVGImageElement::IsAttributeMapped(const nsAtom* name) const {
275 return IsInLengthInfo(name, sLengthInfo) ||
276 SVGImageElementBase::IsAttributeMapped(name);
279 //----------------------------------------------------------------------
280 // SVGElement methods
282 /* virtual */
283 bool SVGImageElement::HasValidDimensions() const {
284 float width, height;
286 if (SVGGeometryProperty::ResolveAll<SVGT::Width, SVGT::Height>(this, &width,
287 &height)) {
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