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/dom/SVGFEImageElement.h"
8 :
9 : #include "mozilla/EventStateManager.h"
10 : #include "mozilla/EventStates.h"
11 : #include "mozilla/dom/SVGFEImageElementBinding.h"
12 : #include "mozilla/dom/SVGFilterElement.h"
13 : #include "mozilla/gfx/2D.h"
14 : #include "mozilla/RefPtr.h"
15 : #include "nsContentUtils.h"
16 : #include "nsLayoutUtils.h"
17 : #include "nsSVGUtils.h"
18 : #include "nsNetUtil.h"
19 : #include "imgIContainer.h"
20 : #include "gfx2DGlue.h"
21 :
22 0 : NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(FEImage)
23 :
24 : using namespace mozilla::gfx;
25 :
26 : namespace mozilla {
27 : namespace dom {
28 :
29 : JSObject*
30 0 : SVGFEImageElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
31 : {
32 0 : return SVGFEImageElementBinding::Wrap(aCx, this, aGivenProto);
33 : }
34 :
35 : nsSVGElement::StringInfo SVGFEImageElement::sStringInfo[3] =
36 : {
37 : { &nsGkAtoms::result, kNameSpaceID_None, true },
38 : { &nsGkAtoms::href, kNameSpaceID_None, true },
39 : { &nsGkAtoms::href, kNameSpaceID_XLink, true }
40 : };
41 :
42 : //----------------------------------------------------------------------
43 : // nsISupports methods
44 :
45 0 : NS_IMPL_ISUPPORTS_INHERITED(SVGFEImageElement, SVGFEImageElementBase,
46 : nsIDOMNode, nsIDOMElement, nsIDOMSVGElement,
47 : imgINotificationObserver, nsIImageLoadingContent,
48 : imgIOnloadBlocker)
49 :
50 : //----------------------------------------------------------------------
51 : // Implementation
52 :
53 0 : SVGFEImageElement::SVGFEImageElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
54 0 : : SVGFEImageElementBase(aNodeInfo)
55 : {
56 : // We start out broken
57 0 : AddStatesSilently(NS_EVENT_STATE_BROKEN);
58 0 : }
59 :
60 0 : SVGFEImageElement::~SVGFEImageElement()
61 : {
62 0 : DestroyImageLoadingContent();
63 0 : }
64 :
65 : //----------------------------------------------------------------------
66 :
67 : nsresult
68 0 : SVGFEImageElement::LoadSVGImage(bool aForce, bool aNotify)
69 : {
70 : // resolve href attribute
71 0 : nsCOMPtr<nsIURI> baseURI = GetBaseURI();
72 :
73 0 : nsAutoString href;
74 0 : if (mStringAttributes[HREF].IsExplicitlySet()) {
75 0 : mStringAttributes[HREF].GetAnimValue(href, this);
76 : } else {
77 0 : mStringAttributes[XLINK_HREF].GetAnimValue(href, this);
78 : }
79 0 : href.Trim(" \t\n\r");
80 :
81 0 : if (baseURI && !href.IsEmpty())
82 0 : NS_MakeAbsoluteURI(href, href, baseURI);
83 :
84 : // Make sure we don't get in a recursive death-spiral
85 0 : nsIDocument* doc = OwnerDoc();
86 0 : nsCOMPtr<nsIURI> hrefAsURI;
87 0 : if (NS_SUCCEEDED(StringToURI(href, doc, getter_AddRefs(hrefAsURI)))) {
88 : bool isEqual;
89 0 : if (NS_SUCCEEDED(hrefAsURI->Equals(baseURI, &isEqual)) && isEqual) {
90 : // Image URI matches our URI exactly! Bail out.
91 0 : return NS_OK;
92 : }
93 : }
94 :
95 : // Mark channel as urgent-start before load image if the image load is
96 : // initaiated by a user interaction.
97 0 : mUseUrgentStartForChannel = EventStateManager::IsHandlingUserInput();
98 0 : return LoadImage(href, aForce, aNotify, eImageLoadType_Normal);
99 : }
100 :
101 : //----------------------------------------------------------------------
102 : // EventTarget methods:
103 :
104 : void
105 0 : SVGFEImageElement::AsyncEventRunning(AsyncEventDispatcher* aEvent)
106 : {
107 0 : nsImageLoadingContent::AsyncEventRunning(aEvent);
108 0 : }
109 :
110 : //----------------------------------------------------------------------
111 : // nsIContent methods:
112 :
113 : NS_IMETHODIMP_(bool)
114 0 : SVGFEImageElement::IsAttributeMapped(const nsIAtom* name) const
115 : {
116 : static const MappedAttributeEntry* const map[] = {
117 : sGraphicsMap
118 : };
119 :
120 0 : return FindAttributeDependence(name, map) ||
121 0 : SVGFEImageElementBase::IsAttributeMapped(name);
122 : }
123 :
124 : nsresult
125 0 : SVGFEImageElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
126 : const nsAttrValue* aValue,
127 : const nsAttrValue* aOldValue, bool aNotify)
128 : {
129 0 : if (aName == nsGkAtoms::href &&
130 0 : (aNamespaceID == kNameSpaceID_XLink ||
131 : aNamespaceID == kNameSpaceID_None)) {
132 :
133 0 : if (aValue) {
134 0 : LoadSVGImage(true, aNotify);
135 : } else {
136 0 : CancelImageRequests(aNotify);
137 : }
138 : }
139 :
140 0 : return SVGFEImageElementBase::AfterSetAttr(aNamespaceID, aName,
141 0 : aValue, aOldValue, aNotify);
142 : }
143 :
144 : void
145 0 : SVGFEImageElement::MaybeLoadSVGImage()
146 : {
147 0 : if ((mStringAttributes[HREF].IsExplicitlySet() ||
148 0 : mStringAttributes[XLINK_HREF].IsExplicitlySet() ) &&
149 0 : (NS_FAILED(LoadSVGImage(false, true)) ||
150 0 : !LoadingEnabled())) {
151 0 : CancelImageRequests(true);
152 : }
153 0 : }
154 :
155 : nsresult
156 0 : SVGFEImageElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
157 : nsIContent* aBindingParent,
158 : bool aCompileEventHandlers)
159 : {
160 0 : nsresult rv = SVGFEImageElementBase::BindToTree(aDocument, aParent,
161 : aBindingParent,
162 0 : aCompileEventHandlers);
163 0 : NS_ENSURE_SUCCESS(rv, rv);
164 :
165 0 : nsImageLoadingContent::BindToTree(aDocument, aParent, aBindingParent,
166 0 : aCompileEventHandlers);
167 :
168 0 : if (mStringAttributes[HREF].IsExplicitlySet() ||
169 0 : mStringAttributes[XLINK_HREF].IsExplicitlySet()) {
170 : // FIXME: Bug 660963 it would be nice if we could just have
171 : // ClearBrokenState update our state and do it fast...
172 0 : ClearBrokenState();
173 0 : RemoveStatesSilently(NS_EVENT_STATE_BROKEN);
174 0 : nsContentUtils::AddScriptRunner(
175 0 : NewRunnableMethod("dom::SVGFEImageElement::MaybeLoadSVGImage",
176 : this,
177 0 : &SVGFEImageElement::MaybeLoadSVGImage));
178 : }
179 :
180 0 : return rv;
181 : }
182 :
183 : void
184 0 : SVGFEImageElement::UnbindFromTree(bool aDeep, bool aNullParent)
185 : {
186 0 : nsImageLoadingContent::UnbindFromTree(aDeep, aNullParent);
187 0 : SVGFEImageElementBase::UnbindFromTree(aDeep, aNullParent);
188 0 : }
189 :
190 : EventStates
191 0 : SVGFEImageElement::IntrinsicState() const
192 : {
193 0 : return SVGFEImageElementBase::IntrinsicState() |
194 0 : nsImageLoadingContent::ImageState();
195 : }
196 :
197 : //----------------------------------------------------------------------
198 : // nsIDOMNode methods
199 :
200 0 : NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFEImageElement)
201 :
202 : already_AddRefed<SVGAnimatedString>
203 0 : SVGFEImageElement::Href()
204 : {
205 0 : return mStringAttributes[HREF].IsExplicitlySet()
206 : ? mStringAttributes[HREF].ToDOMAnimatedString(this)
207 0 : : mStringAttributes[XLINK_HREF].ToDOMAnimatedString(this);
208 : }
209 :
210 : //----------------------------------------------------------------------
211 : // nsIDOMSVGFEImageElement methods
212 :
213 : FilterPrimitiveDescription
214 0 : SVGFEImageElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
215 : const IntRect& aFilterSubregion,
216 : const nsTArray<bool>& aInputsAreTainted,
217 : nsTArray<RefPtr<SourceSurface>>& aInputImages)
218 : {
219 0 : nsIFrame* frame = GetPrimaryFrame();
220 0 : if (!frame) {
221 0 : return FilterPrimitiveDescription(PrimitiveType::Empty);
222 : }
223 :
224 0 : nsCOMPtr<imgIRequest> currentRequest;
225 0 : GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
226 0 : getter_AddRefs(currentRequest));
227 :
228 0 : nsCOMPtr<imgIContainer> imageContainer;
229 0 : if (currentRequest) {
230 0 : currentRequest->GetImage(getter_AddRefs(imageContainer));
231 : }
232 :
233 0 : RefPtr<SourceSurface> image;
234 0 : if (imageContainer) {
235 0 : uint32_t flags = imgIContainer::FLAG_SYNC_DECODE | imgIContainer::FLAG_ASYNC_NOTIFY;
236 0 : image = imageContainer->GetFrame(imgIContainer::FRAME_CURRENT, flags);
237 : }
238 :
239 0 : if (!image) {
240 0 : return FilterPrimitiveDescription(PrimitiveType::Empty);
241 : }
242 :
243 0 : IntSize nativeSize;
244 0 : imageContainer->GetWidth(&nativeSize.width);
245 0 : imageContainer->GetHeight(&nativeSize.height);
246 :
247 : Matrix viewBoxTM =
248 0 : SVGContentUtils::GetViewBoxTransform(aFilterSubregion.width, aFilterSubregion.height,
249 0 : 0, 0, nativeSize.width, nativeSize.height,
250 0 : mPreserveAspectRatio);
251 0 : Matrix TM = viewBoxTM;
252 0 : TM.PostTranslate(aFilterSubregion.x, aFilterSubregion.y);
253 :
254 0 : SamplingFilter samplingFilter = nsLayoutUtils::GetSamplingFilterForFrame(frame);
255 :
256 0 : FilterPrimitiveDescription descr(PrimitiveType::Image);
257 0 : descr.Attributes().Set(eImageFilter, (uint32_t)samplingFilter);
258 0 : descr.Attributes().Set(eImageTransform, TM);
259 :
260 : // Append the image to aInputImages and store its index in the description.
261 0 : size_t imageIndex = aInputImages.Length();
262 0 : aInputImages.AppendElement(image);
263 0 : descr.Attributes().Set(eImageInputIndex, (uint32_t)imageIndex);
264 :
265 0 : return descr;
266 : }
267 :
268 : bool
269 0 : SVGFEImageElement::AttributeAffectsRendering(int32_t aNameSpaceID,
270 : nsIAtom* aAttribute) const
271 : {
272 : // nsGkAtoms::href is deliberately omitted as the frame has special
273 : // handling to load the image
274 0 : return SVGFEImageElementBase::AttributeAffectsRendering(aNameSpaceID, aAttribute) ||
275 0 : (aNameSpaceID == kNameSpaceID_None &&
276 0 : aAttribute == nsGkAtoms::preserveAspectRatio);
277 : }
278 :
279 : bool
280 0 : SVGFEImageElement::OutputIsTainted(const nsTArray<bool>& aInputsAreTainted,
281 : nsIPrincipal* aReferencePrincipal)
282 : {
283 : nsresult rv;
284 0 : nsCOMPtr<imgIRequest> currentRequest;
285 0 : GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
286 0 : getter_AddRefs(currentRequest));
287 :
288 0 : if (!currentRequest) {
289 0 : return false;
290 : }
291 :
292 : uint32_t status;
293 0 : currentRequest->GetImageStatus(&status);
294 0 : if ((status & imgIRequest::STATUS_LOAD_COMPLETE) == 0) {
295 : // The load has not completed yet.
296 0 : return false;
297 : }
298 :
299 0 : nsCOMPtr<nsIPrincipal> principal;
300 0 : rv = currentRequest->GetImagePrincipal(getter_AddRefs(principal));
301 0 : if (NS_FAILED(rv) || !principal) {
302 0 : return true;
303 : }
304 :
305 : int32_t corsmode;
306 0 : if (NS_SUCCEEDED(currentRequest->GetCORSMode(&corsmode)) &&
307 0 : corsmode != imgIRequest::CORS_NONE) {
308 : // If CORS was used to load the image, the page is allowed to read from it.
309 0 : return false;
310 : }
311 :
312 0 : if (aReferencePrincipal->Subsumes(principal)) {
313 : // The page is allowed to read from the image.
314 0 : return false;
315 : }
316 :
317 0 : return true;
318 : }
319 :
320 : //----------------------------------------------------------------------
321 : // nsSVGElement methods
322 :
323 : already_AddRefed<DOMSVGAnimatedPreserveAspectRatio>
324 0 : SVGFEImageElement::PreserveAspectRatio()
325 : {
326 0 : return mPreserveAspectRatio.ToDOMAnimatedPreserveAspectRatio(this);
327 : }
328 :
329 : SVGAnimatedPreserveAspectRatio *
330 0 : SVGFEImageElement::GetPreserveAspectRatio()
331 : {
332 0 : return &mPreserveAspectRatio;
333 : }
334 :
335 : nsSVGElement::StringAttributesInfo
336 0 : SVGFEImageElement::GetStringInfo()
337 : {
338 : return StringAttributesInfo(mStringAttributes, sStringInfo,
339 0 : ArrayLength(sStringInfo));
340 : }
341 :
342 : //----------------------------------------------------------------------
343 : // imgINotificationObserver methods
344 :
345 : NS_IMETHODIMP
346 0 : SVGFEImageElement::Notify(imgIRequest* aRequest, int32_t aType, const nsIntRect* aData)
347 : {
348 0 : nsresult rv = nsImageLoadingContent::Notify(aRequest, aType, aData);
349 :
350 0 : if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
351 : // Request a decode
352 0 : nsCOMPtr<imgIContainer> container;
353 0 : aRequest->GetImage(getter_AddRefs(container));
354 0 : MOZ_ASSERT(container, "who sent the notification then?");
355 0 : container->StartDecoding(imgIContainer::FLAG_NONE);
356 : }
357 :
358 0 : if (aType == imgINotificationObserver::LOAD_COMPLETE ||
359 0 : aType == imgINotificationObserver::FRAME_UPDATE ||
360 : aType == imgINotificationObserver::SIZE_AVAILABLE) {
361 0 : Invalidate();
362 : }
363 :
364 0 : return rv;
365 : }
366 :
367 : //----------------------------------------------------------------------
368 : // helper methods
369 :
370 : void
371 0 : SVGFEImageElement::Invalidate()
372 : {
373 0 : if (GetParent() && GetParent()->IsSVGElement(nsGkAtoms::filter)) {
374 0 : static_cast<SVGFilterElement*>(GetParent())->Invalidate();
375 : }
376 0 : }
377 :
378 : } // namespace dom
379 : } // namespace mozilla
|