SVGSVGElement.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  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. #ifndef mozilla_dom_SVGSVGElement_h
  6. #define mozilla_dom_SVGSVGElement_h
  7. #include "mozilla/dom/FromParser.h"
  8. #include "nsAutoPtr.h"
  9. #include "nsIContentInlines.h"
  10. #include "nsISVGPoint.h"
  11. #include "nsSVGEnum.h"
  12. #include "nsSVGLength2.h"
  13. #include "SVGGraphicsElement.h"
  14. #include "SVGImageContext.h"
  15. #include "nsSVGViewBox.h"
  16. #include "SVGPreserveAspectRatio.h"
  17. #include "SVGAnimatedPreserveAspectRatio.h"
  18. #include "mozilla/Attributes.h"
  19. nsresult NS_NewSVGSVGElement(nsIContent **aResult,
  20. already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
  21. mozilla::dom::FromParser aFromParser);
  22. class nsSMILTimeContainer;
  23. class nsSVGOuterSVGFrame;
  24. class nsSVGInnerSVGFrame;
  25. namespace mozilla {
  26. class AutoSVGRenderingState;
  27. class DOMSVGAnimatedPreserveAspectRatio;
  28. class DOMSVGLength;
  29. class DOMSVGNumber;
  30. class EventChainPreVisitor;
  31. class SVGFragmentIdentifier;
  32. class AutoSVGViewHandler;
  33. namespace dom {
  34. class SVGAngle;
  35. class SVGAnimatedRect;
  36. class SVGMatrix;
  37. class SVGTransform;
  38. class SVGViewElement;
  39. class SVGIRect;
  40. class SVGSVGElement;
  41. class DOMSVGTranslatePoint final : public nsISVGPoint {
  42. public:
  43. DOMSVGTranslatePoint(SVGPoint* aPt, SVGSVGElement *aElement)
  44. : nsISVGPoint(aPt, true), mElement(aElement) {}
  45. explicit DOMSVGTranslatePoint(DOMSVGTranslatePoint* aPt)
  46. : nsISVGPoint(&aPt->mPt, true), mElement(aPt->mElement) {}
  47. NS_DECL_ISUPPORTS_INHERITED
  48. NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DOMSVGTranslatePoint, nsISVGPoint)
  49. virtual DOMSVGPoint* Copy() override;
  50. // WebIDL
  51. virtual float X() override { return mPt.GetX(); }
  52. virtual float Y() override { return mPt.GetY(); }
  53. virtual void SetX(float aValue, ErrorResult& rv) override;
  54. virtual void SetY(float aValue, ErrorResult& rv) override;
  55. virtual already_AddRefed<nsISVGPoint> MatrixTransform(SVGMatrix& matrix) override;
  56. virtual nsISupports* GetParentObject() override;
  57. RefPtr<SVGSVGElement> mElement;
  58. private:
  59. ~DOMSVGTranslatePoint() {}
  60. };
  61. class svgFloatSize {
  62. public:
  63. svgFloatSize(float aWidth, float aHeight)
  64. : width(aWidth)
  65. , height(aHeight)
  66. {}
  67. bool operator!=(const svgFloatSize& rhs) {
  68. return width != rhs.width || height != rhs.height;
  69. }
  70. float width;
  71. float height;
  72. };
  73. // Stores svgView arguments of SVG fragment identifiers.
  74. class SVGView {
  75. friend class mozilla::AutoSVGViewHandler;
  76. friend class mozilla::dom::SVGSVGElement;
  77. public:
  78. SVGView();
  79. private:
  80. nsSVGEnum mZoomAndPan;
  81. nsSVGViewBox mViewBox;
  82. SVGAnimatedPreserveAspectRatio mPreserveAspectRatio;
  83. nsAutoPtr<nsSVGAnimatedTransformList> mTransforms;
  84. };
  85. typedef SVGGraphicsElement SVGSVGElementBase;
  86. class SVGSVGElement final : public SVGSVGElementBase
  87. {
  88. friend class ::nsSVGOuterSVGFrame;
  89. friend class ::nsSVGInnerSVGFrame;
  90. friend class mozilla::dom::SVGView;
  91. friend class mozilla::SVGFragmentIdentifier;
  92. friend class mozilla::AutoSVGViewHandler;
  93. friend class mozilla::AutoSVGRenderingState;
  94. SVGSVGElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
  95. FromParser aFromParser);
  96. virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
  97. friend nsresult (::NS_NewSVGSVGElement(nsIContent **aResult,
  98. already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
  99. mozilla::dom::FromParser aFromParser));
  100. ~SVGSVGElement();
  101. public:
  102. // interfaces:
  103. NS_DECL_ISUPPORTS_INHERITED
  104. NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(SVGSVGElement, SVGSVGElementBase)
  105. /**
  106. * For use by zoom controls to allow currentScale, currentTranslate.x and
  107. * currentTranslate.y to be set by a single operation that dispatches a
  108. * single SVGZoom event (instead of one SVGZoom and two SVGScroll events).
  109. */
  110. void SetCurrentScaleTranslate(float s, float x, float y);
  111. /**
  112. * Retrieve the value of currentScale and currentTranslate.
  113. */
  114. const SVGPoint& GetCurrentTranslate() { return mCurrentTranslate; }
  115. float GetCurrentScale() { return mCurrentScale; }
  116. /**
  117. * Retrieve the value of currentScale, currentTranslate.x or
  118. * currentTranslate.y prior to the last change made to any one of them.
  119. */
  120. const SVGPoint& GetPreviousTranslate() { return mPreviousTranslate; }
  121. float GetPreviousScale() { return mPreviousScale; }
  122. nsSMILTimeContainer* GetTimedDocumentRoot();
  123. // nsIContent interface
  124. NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
  125. virtual nsresult GetEventTargetParent(
  126. EventChainPreVisitor& aVisitor) override;
  127. virtual bool IsEventAttributeName(nsIAtom* aName) override;
  128. // nsSVGElement specializations:
  129. virtual gfxMatrix PrependLocalTransformsTo(
  130. const gfxMatrix &aMatrix,
  131. SVGTransformTypes aWhich = eAllTransforms) const override;
  132. virtual nsSVGAnimatedTransformList*
  133. GetAnimatedTransformList(uint32_t aFlags = 0) override;
  134. virtual bool HasValidDimensions() const override;
  135. // SVGSVGElement methods:
  136. float GetLength(uint8_t mCtxType);
  137. // public helpers:
  138. /**
  139. * Returns -1 if the width/height is a percentage, else returns the user unit
  140. * length clamped to fit in a int32_t.
  141. * XXX see bug 1112533 comment 3 - we should fix drawImage so that we can
  142. * change these methods to make zero the error flag for percentages.
  143. */
  144. int32_t GetIntrinsicWidth();
  145. int32_t GetIntrinsicHeight();
  146. /**
  147. * Returns true if this element has a base/anim value for its "viewBox"
  148. * attribute that defines a viewBox rectangle with finite values, or
  149. * if there is a view element overriding this element's viewBox and it
  150. * has a valid viewBox.
  151. *
  152. * Note that this does not check whether we need to synthesize a viewBox,
  153. * so you must call ShouldSynthesizeViewBox() if you need to check that too.
  154. *
  155. * Note also that this method does not pay attention to whether the width or
  156. * height values of the viewBox rect are positive!
  157. */
  158. bool HasViewBoxRect() const;
  159. /**
  160. * Returns true if we should synthesize a viewBox for ourselves (that is, if
  161. * we're the root element in an image document, and we're not currently being
  162. * painted for an <svg:image> element).
  163. *
  164. * Only call this method if HasViewBoxRect() returns false.
  165. */
  166. bool ShouldSynthesizeViewBox() const;
  167. bool HasViewBoxOrSyntheticViewBox() const {
  168. return HasViewBoxRect() || ShouldSynthesizeViewBox();
  169. }
  170. gfx::Matrix GetViewBoxTransform() const;
  171. bool HasChildrenOnlyTransform() const {
  172. return mHasChildrenOnlyTransform;
  173. }
  174. void UpdateHasChildrenOnlyTransform();
  175. enum ChildrenOnlyTransformChangedFlags {
  176. eDuringReflow = 1
  177. };
  178. /**
  179. * This method notifies the style system that the overflow rects of our
  180. * immediate childrens' frames need to be updated. It is called by our own
  181. * frame when changes (e.g. to currentScale) cause our children-only
  182. * transform to change.
  183. *
  184. * The reason we have this method instead of overriding
  185. * GetAttributeChangeHint is because we need to act on non-attribute (e.g.
  186. * currentScale) changes in addition to attribute (e.g. viewBox) changes.
  187. */
  188. void ChildrenOnlyTransformChanged(uint32_t aFlags = 0);
  189. // This services any pending notifications for the transform on on this root
  190. // <svg> node needing to be recalculated. (Only applicable in
  191. // SVG-as-an-image documents.)
  192. virtual void FlushImageTransformInvalidation();
  193. virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
  194. // Returns true IFF our attributes are currently overridden by a <view>
  195. // element and that element's ID matches the passed-in string.
  196. bool IsOverriddenBy(const nsAString &aViewID) const {
  197. return mCurrentViewID && mCurrentViewID->Equals(aViewID);
  198. }
  199. svgFloatSize GetViewportSize() const {
  200. return svgFloatSize(mViewportWidth, mViewportHeight);
  201. }
  202. void SetViewportSize(const svgFloatSize& aSize) {
  203. mViewportWidth = aSize.width;
  204. mViewportHeight = aSize.height;
  205. }
  206. // WebIDL
  207. already_AddRefed<SVGAnimatedLength> X();
  208. already_AddRefed<SVGAnimatedLength> Y();
  209. already_AddRefed<SVGAnimatedLength> Width();
  210. already_AddRefed<SVGAnimatedLength> Height();
  211. float PixelUnitToMillimeterX();
  212. float PixelUnitToMillimeterY();
  213. float ScreenPixelToMillimeterX();
  214. float ScreenPixelToMillimeterY();
  215. bool UseCurrentView();
  216. float CurrentScale();
  217. void SetCurrentScale(float aCurrentScale);
  218. already_AddRefed<nsISVGPoint> CurrentTranslate();
  219. void SetCurrentTranslate(float x, float y);
  220. uint32_t SuspendRedraw(uint32_t max_wait_milliseconds);
  221. void UnsuspendRedraw(uint32_t suspend_handle_id);
  222. void UnsuspendRedrawAll();
  223. void ForceRedraw();
  224. void PauseAnimations();
  225. void UnpauseAnimations();
  226. bool AnimationsPaused();
  227. float GetCurrentTime();
  228. void SetCurrentTime(float seconds);
  229. void DeselectAll();
  230. already_AddRefed<DOMSVGNumber> CreateSVGNumber();
  231. already_AddRefed<DOMSVGLength> CreateSVGLength();
  232. already_AddRefed<SVGAngle> CreateSVGAngle();
  233. already_AddRefed<nsISVGPoint> CreateSVGPoint();
  234. already_AddRefed<SVGMatrix> CreateSVGMatrix();
  235. already_AddRefed<SVGIRect> CreateSVGRect();
  236. already_AddRefed<SVGTransform> CreateSVGTransform();
  237. already_AddRefed<SVGTransform> CreateSVGTransformFromMatrix(SVGMatrix& matrix);
  238. using nsINode::GetElementById; // This does what we want
  239. already_AddRefed<SVGAnimatedRect> ViewBox();
  240. already_AddRefed<DOMSVGAnimatedPreserveAspectRatio> PreserveAspectRatio();
  241. uint16_t ZoomAndPan();
  242. void SetZoomAndPan(uint16_t aZoomAndPan, ErrorResult& rv);
  243. virtual nsSVGViewBox* GetViewBox() override;
  244. private:
  245. // nsSVGElement overrides
  246. virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
  247. nsIContent* aBindingParent,
  248. bool aCompileEventHandlers) override;
  249. virtual void UnbindFromTree(bool aDeep, bool aNullParent) override;
  250. // implementation helpers:
  251. SVGViewElement* GetCurrentViewElement() const;
  252. // Methods for <image> elements to override my "PreserveAspectRatio" value.
  253. // These are private so that only our friends (AutoSVGRenderingState in
  254. // particular) have access.
  255. void SetImageOverridePreserveAspectRatio(const SVGPreserveAspectRatio& aPAR);
  256. void ClearImageOverridePreserveAspectRatio();
  257. // Set/Clear properties to hold old version of preserveAspectRatio
  258. // when it's being overridden by an <image> element that we are inside of.
  259. bool SetPreserveAspectRatioProperty(const SVGPreserveAspectRatio& aPAR);
  260. const SVGPreserveAspectRatio* GetPreserveAspectRatioProperty() const;
  261. bool ClearPreserveAspectRatioProperty();
  262. void SetIsPaintingForSVGImageElement(bool aIsPaintingSVGImageElement);
  263. bool IsRoot() const {
  264. NS_ASSERTION((IsInUncomposedDoc() && !GetParent()) ==
  265. (OwnerDoc() && (OwnerDoc()->GetRootElement() == this)),
  266. "Can't determine if we're root");
  267. return IsInUncomposedDoc() && !GetParent();
  268. }
  269. /**
  270. * Returns true if this is an SVG <svg> element that is the child of
  271. * another non-foreignObject SVG element.
  272. */
  273. bool IsInner() const {
  274. const nsIContent *parent = GetFlattenedTreeParent();
  275. return parent && parent->IsSVGElement() &&
  276. !parent->IsSVGElement(nsGkAtoms::foreignObject);
  277. }
  278. /*
  279. * While binding to the tree we need to determine if we will be the outermost
  280. * <svg> element _before_ the children are bound (as they want to know what
  281. * timed document root to register with) and therefore _before_ our parent is
  282. * set (both actions are performed by Element::BindToTree) so we
  283. * can't use GetOwnerSVGElement() as it relies on GetParent(). This code is
  284. * basically a simplified version of GetOwnerSVGElement that uses the parent
  285. * parameters passed in instead.
  286. */
  287. bool WillBeOutermostSVG(nsIContent* aParent,
  288. nsIContent* aBindingParent) const;
  289. // invalidate viewbox -> viewport xform & inform frames
  290. void InvalidateTransformNotifyFrame();
  291. // Returns true if we have at least one of the following:
  292. // - a (valid or invalid) value for the preserveAspectRatio attribute
  293. // - a SMIL-animated value for the preserveAspectRatio attribute
  294. bool HasPreserveAspectRatio();
  295. /**
  296. * Returns the explicit viewBox rect, if specified, or else a synthesized
  297. * viewBox, if appropriate, or else a viewBox matching the dimensions of the
  298. * SVG viewport.
  299. */
  300. nsSVGViewBoxRect GetViewBoxWithSynthesis(
  301. float aViewportWidth, float aViewportHeight) const;
  302. /**
  303. * Returns the explicit or default preserveAspectRatio, unless we're
  304. * synthesizing a viewBox, in which case it returns the "none" value.
  305. */
  306. SVGPreserveAspectRatio GetPreserveAspectRatioWithOverride() const;
  307. virtual LengthAttributesInfo GetLengthInfo() override;
  308. enum { ATTR_X, ATTR_Y, ATTR_WIDTH, ATTR_HEIGHT };
  309. nsSVGLength2 mLengthAttributes[4];
  310. static LengthInfo sLengthInfo[4];
  311. virtual EnumAttributesInfo GetEnumInfo() override;
  312. enum { ZOOMANDPAN };
  313. nsSVGEnum mEnumAttributes[1];
  314. static nsSVGEnumMapping sZoomAndPanMap[];
  315. static EnumInfo sEnumInfo[1];
  316. virtual SVGAnimatedPreserveAspectRatio *GetPreserveAspectRatio() override;
  317. nsSVGViewBox mViewBox;
  318. SVGAnimatedPreserveAspectRatio mPreserveAspectRatio;
  319. // mCurrentViewID and mSVGView are mutually exclusive; we can have
  320. // at most one non-null.
  321. nsAutoPtr<nsString> mCurrentViewID;
  322. nsAutoPtr<SVGView> mSVGView;
  323. // The size of the rectangular SVG viewport into which we render. This is
  324. // not (necessarily) the same as the content area. See:
  325. //
  326. // http://www.w3.org/TR/SVG11/coords.html#ViewportSpace
  327. //
  328. // XXXjwatt Currently only used for outer <svg>, but maybe we could use -1 to
  329. // flag this as an inner <svg> to save the overhead of GetCtx calls?
  330. // XXXjwatt our frame should probably reset these when it's destroyed.
  331. float mViewportWidth, mViewportHeight;
  332. // The time container for animations within this SVG document fragment. Set
  333. // for all outermost <svg> elements (not nested <svg> elements).
  334. nsAutoPtr<nsSMILTimeContainer> mTimedDocumentRoot;
  335. // zoom and pan
  336. // IMPORTANT: see the comment in RecordCurrentScaleTranslate before writing
  337. // code to change any of these!
  338. SVGPoint mCurrentTranslate;
  339. float mCurrentScale;
  340. SVGPoint mPreviousTranslate;
  341. float mPreviousScale;
  342. // For outermost <svg> elements created from parsing, animation is started by
  343. // the onload event in accordance with the SVG spec, but for <svg> elements
  344. // created by script or promoted from inner <svg> to outermost <svg> we need
  345. // to manually kick off animation when they are bound to the tree.
  346. bool mStartAnimationOnBindToTree;
  347. bool mImageNeedsTransformInvalidation;
  348. bool mIsPaintingSVGImageElement;
  349. bool mHasChildrenOnlyTransform;
  350. };
  351. } // namespace dom
  352. // Helper class to automatically manage temporary changes to an SVG document's
  353. // state for rendering purposes.
  354. class MOZ_RAII AutoSVGRenderingState
  355. {
  356. public:
  357. AutoSVGRenderingState(const Maybe<SVGImageContext>& aSVGContext,
  358. float aFrameTime,
  359. dom::SVGSVGElement* aRootElem
  360. MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
  361. : mHaveOverrides(aSVGContext.isSome() &&
  362. aSVGContext->GetPreserveAspectRatio().isSome())
  363. , mRootElem(aRootElem)
  364. {
  365. MOZ_GUARD_OBJECT_NOTIFIER_INIT;
  366. MOZ_ASSERT(mRootElem, "No SVG node to manage?");
  367. if (mHaveOverrides) {
  368. // Override preserveAspectRatio in our helper document.
  369. // XXXdholbert We should technically be overriding the helper doc's clip
  370. // and overflow properties here, too. See bug 272288 comment 36.
  371. mRootElem->SetImageOverridePreserveAspectRatio(
  372. *aSVGContext->GetPreserveAspectRatio());
  373. mRootElem->SetIsPaintingForSVGImageElement(
  374. aSVGContext->IsPaintingForSVGImageElement());
  375. }
  376. mOriginalTime = mRootElem->GetCurrentTime();
  377. mRootElem->SetCurrentTime(aFrameTime); // Does nothing if there's no change.
  378. }
  379. ~AutoSVGRenderingState()
  380. {
  381. mRootElem->SetCurrentTime(mOriginalTime);
  382. if (mHaveOverrides) {
  383. mRootElem->ClearImageOverridePreserveAspectRatio();
  384. mRootElem->SetIsPaintingForSVGImageElement(false);
  385. }
  386. }
  387. private:
  388. const bool mHaveOverrides;
  389. float mOriginalTime;
  390. const RefPtr<dom::SVGSVGElement> mRootElem;
  391. MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
  392. };
  393. } // namespace mozilla
  394. #endif // SVGSVGElement_h