Line data Source code
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/. */
6 :
7 : #include "mozilla/ArrayUtils.h"
8 : #include "mozilla/EventStateManager.h"
9 : #include "mozilla/EventStates.h"
10 :
11 : #include "mozilla/dom/SVGImageElement.h"
12 : #include "mozilla/gfx/2D.h"
13 : #include "nsCOMPtr.h"
14 : #include "nsIURI.h"
15 : #include "nsNetUtil.h"
16 : #include "imgINotificationObserver.h"
17 : #include "mozilla/dom/SVGImageElementBinding.h"
18 : #include "nsContentUtils.h"
19 :
20 0 : NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Image)
21 :
22 : using namespace mozilla::gfx;
23 :
24 : namespace mozilla {
25 : namespace dom {
26 :
27 : JSObject*
28 0 : SVGImageElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
29 : {
30 0 : return SVGImageElementBinding::Wrap(aCx, this, aGivenProto);
31 : }
32 :
33 : nsSVGElement::LengthInfo SVGImageElement::sLengthInfo[4] =
34 : {
35 : { &nsGkAtoms::x, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, SVGContentUtils::X },
36 : { &nsGkAtoms::y, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, SVGContentUtils::Y },
37 : { &nsGkAtoms::width, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, SVGContentUtils::X },
38 : { &nsGkAtoms::height, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, SVGContentUtils::Y },
39 : };
40 :
41 : nsSVGElement::StringInfo SVGImageElement::sStringInfo[2] =
42 : {
43 : { &nsGkAtoms::href, kNameSpaceID_None, true },
44 : { &nsGkAtoms::href, kNameSpaceID_XLink, true }
45 : };
46 :
47 : //----------------------------------------------------------------------
48 : // nsISupports methods
49 :
50 0 : NS_IMPL_ISUPPORTS_INHERITED(SVGImageElement, SVGImageElementBase,
51 : nsIDOMNode, nsIDOMElement,
52 : nsIDOMSVGElement,
53 : imgINotificationObserver,
54 : nsIImageLoadingContent, imgIOnloadBlocker)
55 :
56 : //----------------------------------------------------------------------
57 : // Implementation
58 :
59 0 : SVGImageElement::SVGImageElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
60 0 : : SVGImageElementBase(aNodeInfo)
61 : {
62 : // We start out broken
63 0 : AddStatesSilently(NS_EVENT_STATE_BROKEN);
64 0 : }
65 :
66 0 : SVGImageElement::~SVGImageElement()
67 : {
68 0 : DestroyImageLoadingContent();
69 0 : }
70 :
71 : //----------------------------------------------------------------------
72 : // nsIDOMNode methods
73 :
74 :
75 0 : NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGImageElement)
76 :
77 :
78 : //----------------------------------------------------------------------
79 :
80 : already_AddRefed<SVGAnimatedLength>
81 0 : SVGImageElement::X()
82 : {
83 0 : return mLengthAttributes[ATTR_X].ToDOMAnimatedLength(this);
84 : }
85 :
86 : already_AddRefed<SVGAnimatedLength>
87 0 : SVGImageElement::Y()
88 : {
89 0 : return mLengthAttributes[ATTR_Y].ToDOMAnimatedLength(this);
90 : }
91 :
92 : already_AddRefed<SVGAnimatedLength>
93 0 : SVGImageElement::Width()
94 : {
95 0 : return mLengthAttributes[ATTR_WIDTH].ToDOMAnimatedLength(this);
96 : }
97 :
98 : already_AddRefed<SVGAnimatedLength>
99 0 : SVGImageElement::Height()
100 : {
101 0 : return mLengthAttributes[ATTR_HEIGHT].ToDOMAnimatedLength(this);
102 : }
103 :
104 : already_AddRefed<DOMSVGAnimatedPreserveAspectRatio>
105 0 : SVGImageElement::PreserveAspectRatio()
106 : {
107 0 : return mPreserveAspectRatio.ToDOMAnimatedPreserveAspectRatio(this);
108 : }
109 :
110 : already_AddRefed<SVGAnimatedString>
111 0 : SVGImageElement::Href()
112 : {
113 0 : return mStringAttributes[HREF].IsExplicitlySet()
114 : ? mStringAttributes[HREF].ToDOMAnimatedString(this)
115 0 : : mStringAttributes[XLINK_HREF].ToDOMAnimatedString(this);
116 : }
117 :
118 : //----------------------------------------------------------------------
119 :
120 : nsresult
121 0 : SVGImageElement::LoadSVGImage(bool aForce, bool aNotify)
122 : {
123 : // resolve href attribute
124 0 : nsCOMPtr<nsIURI> baseURI = GetBaseURI();
125 :
126 0 : nsAutoString href;
127 0 : if (mStringAttributes[HREF].IsExplicitlySet()) {
128 0 : mStringAttributes[HREF].GetAnimValue(href, this);
129 : } else {
130 0 : mStringAttributes[XLINK_HREF].GetAnimValue(href, this);
131 : }
132 0 : href.Trim(" \t\n\r");
133 :
134 0 : if (baseURI && !href.IsEmpty())
135 0 : NS_MakeAbsoluteURI(href, href, baseURI);
136 :
137 : // Mark channel as urgent-start before load image if the image load is
138 : // initaiated by a user interaction.
139 0 : mUseUrgentStartForChannel = EventStateManager::IsHandlingUserInput();
140 :
141 0 : return LoadImage(href, aForce, aNotify, eImageLoadType_Normal);
142 : }
143 :
144 : //----------------------------------------------------------------------
145 : // EventTarget methods:
146 :
147 : void
148 0 : SVGImageElement::AsyncEventRunning(AsyncEventDispatcher* aEvent)
149 : {
150 0 : nsImageLoadingContent::AsyncEventRunning(aEvent);
151 0 : }
152 :
153 : //----------------------------------------------------------------------
154 : // nsIContent methods:
155 :
156 : nsresult
157 0 : SVGImageElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
158 : const nsAttrValue* aValue,
159 : const nsAttrValue* aOldValue, bool aNotify)
160 : {
161 0 : if (aName == nsGkAtoms::href &&
162 0 : (aNamespaceID == kNameSpaceID_None ||
163 : aNamespaceID == kNameSpaceID_XLink)) {
164 :
165 0 : if (aValue) {
166 0 : LoadSVGImage(true, aNotify);
167 : } else {
168 0 : CancelImageRequests(aNotify);
169 : }
170 : }
171 0 : return SVGImageElementBase::AfterSetAttr(aNamespaceID, aName,
172 0 : aValue, aOldValue, aNotify);
173 : }
174 :
175 : void
176 0 : SVGImageElement::MaybeLoadSVGImage()
177 : {
178 0 : if ((mStringAttributes[HREF].IsExplicitlySet() ||
179 0 : mStringAttributes[XLINK_HREF].IsExplicitlySet()) &&
180 0 : (NS_FAILED(LoadSVGImage(false, true)) ||
181 0 : !LoadingEnabled())) {
182 0 : CancelImageRequests(true);
183 : }
184 0 : }
185 :
186 : nsresult
187 0 : SVGImageElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
188 : nsIContent* aBindingParent,
189 : bool aCompileEventHandlers)
190 : {
191 0 : nsresult rv = SVGImageElementBase::BindToTree(aDocument, aParent,
192 : aBindingParent,
193 0 : aCompileEventHandlers);
194 0 : NS_ENSURE_SUCCESS(rv, rv);
195 :
196 0 : nsImageLoadingContent::BindToTree(aDocument, aParent, aBindingParent,
197 0 : aCompileEventHandlers);
198 :
199 0 : if (mStringAttributes[HREF].IsExplicitlySet() ||
200 0 : mStringAttributes[XLINK_HREF].IsExplicitlySet()) {
201 : // FIXME: Bug 660963 it would be nice if we could just have
202 : // ClearBrokenState update our state and do it fast...
203 0 : ClearBrokenState();
204 0 : RemoveStatesSilently(NS_EVENT_STATE_BROKEN);
205 0 : nsContentUtils::AddScriptRunner(
206 0 : NewRunnableMethod("dom::SVGImageElement::MaybeLoadSVGImage",
207 : this,
208 0 : &SVGImageElement::MaybeLoadSVGImage));
209 : }
210 :
211 0 : return rv;
212 : }
213 :
214 : void
215 0 : SVGImageElement::UnbindFromTree(bool aDeep, bool aNullParent)
216 : {
217 0 : nsImageLoadingContent::UnbindFromTree(aDeep, aNullParent);
218 0 : SVGImageElementBase::UnbindFromTree(aDeep, aNullParent);
219 0 : }
220 :
221 : EventStates
222 0 : SVGImageElement::IntrinsicState() const
223 : {
224 0 : return SVGImageElementBase::IntrinsicState() |
225 0 : nsImageLoadingContent::ImageState();
226 : }
227 :
228 : NS_IMETHODIMP_(bool)
229 0 : SVGImageElement::IsAttributeMapped(const nsIAtom* name) const
230 : {
231 : static const MappedAttributeEntry* const map[] = {
232 : sViewportsMap,
233 : };
234 :
235 0 : return FindAttributeDependence(name, map) ||
236 0 : SVGImageElementBase::IsAttributeMapped(name);
237 : }
238 :
239 : //----------------------------------------------------------------------
240 : // SVGGeometryElement methods
241 :
242 : /* For the purposes of the update/invalidation logic pretend to
243 : be a rectangle. */
244 : bool
245 0 : SVGImageElement::GetGeometryBounds(Rect* aBounds,
246 : const StrokeOptions& aStrokeOptions,
247 : const Matrix& aToBoundsSpace,
248 : const Matrix* aToNonScalingStrokeSpace)
249 : {
250 0 : Rect rect;
251 0 : GetAnimatedLengthValues(&rect.x, &rect.y, &rect.width,
252 0 : &rect.height, nullptr);
253 :
254 0 : if (rect.IsEmpty()) {
255 : // Rendering of the element disabled
256 0 : rect.SetEmpty(); // Make sure width/height are zero and not negative
257 : }
258 :
259 0 : *aBounds = aToBoundsSpace.TransformBounds(rect);
260 0 : return true;
261 : }
262 :
263 : already_AddRefed<Path>
264 0 : SVGImageElement::BuildPath(PathBuilder* aBuilder)
265 : {
266 : // We get called in order to get bounds for this element, and for
267 : // hit-testing against it. For that we just pretend to be a rectangle.
268 :
269 : float x, y, width, height;
270 0 : GetAnimatedLengthValues(&x, &y, &width, &height, nullptr);
271 :
272 0 : if (width <= 0 || height <= 0) {
273 0 : return nullptr;
274 : }
275 :
276 0 : Rect r(x, y, width, height);
277 0 : aBuilder->MoveTo(r.TopLeft());
278 0 : aBuilder->LineTo(r.TopRight());
279 0 : aBuilder->LineTo(r.BottomRight());
280 0 : aBuilder->LineTo(r.BottomLeft());
281 0 : aBuilder->Close();
282 :
283 0 : return aBuilder->Finish();
284 : }
285 :
286 : //----------------------------------------------------------------------
287 : // nsSVGElement methods
288 :
289 : /* virtual */ bool
290 0 : SVGImageElement::HasValidDimensions() const
291 : {
292 0 : return mLengthAttributes[ATTR_WIDTH].IsExplicitlySet() &&
293 0 : mLengthAttributes[ATTR_WIDTH].GetAnimValInSpecifiedUnits() > 0 &&
294 0 : mLengthAttributes[ATTR_HEIGHT].IsExplicitlySet() &&
295 0 : mLengthAttributes[ATTR_HEIGHT].GetAnimValInSpecifiedUnits() > 0;
296 : }
297 :
298 : nsSVGElement::LengthAttributesInfo
299 0 : SVGImageElement::GetLengthInfo()
300 : {
301 : return LengthAttributesInfo(mLengthAttributes, sLengthInfo,
302 0 : ArrayLength(sLengthInfo));
303 : }
304 :
305 : SVGAnimatedPreserveAspectRatio *
306 0 : SVGImageElement::GetPreserveAspectRatio()
307 : {
308 0 : return &mPreserveAspectRatio;
309 : }
310 :
311 : nsSVGElement::StringAttributesInfo
312 0 : SVGImageElement::GetStringInfo()
313 : {
314 : return StringAttributesInfo(mStringAttributes, sStringInfo,
315 0 : ArrayLength(sStringInfo));
316 : }
317 :
318 : nsresult
319 0 : SVGImageElement::CopyInnerTo(Element* aDest, bool aPreallocateChildren)
320 : {
321 0 : if (aDest->OwnerDoc()->IsStaticDocument()) {
322 0 : CreateStaticImageClone(static_cast<SVGImageElement*>(aDest));
323 : }
324 0 : return SVGImageElementBase::CopyInnerTo(aDest, aPreallocateChildren);
325 : }
326 :
327 : } // namespace dom
328 : } // namespace mozilla
329 :
|