SVGFEImageElement.cpp 11 KB

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