SVGImageElement.cpp 9.4 KB

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