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 #ifndef mozilla_dom_SVGSVGElement_h
8 #define mozilla_dom_SVGSVGElement_h
9 
10 #include "SVGAnimatedEnumeration.h"
11 #include "SVGViewportElement.h"
12 
13 nsresult NS_NewSVGSVGElement(
14     nsIContent** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
15     mozilla::dom::FromParser aFromParser);
16 
17 namespace mozilla {
18 class AutoSVGViewHandler;
19 class SMILTimeContainer;
20 class SVGFragmentIdentifier;
21 class EventChainPreVisitor;
22 
23 namespace dom {
24 class DOMSVGAngle;
25 class DOMSVGLength;
26 class DOMSVGNumber;
27 class SVGMatrix;
28 class SVGRect;
29 class SVGSVGElement;
30 
31 // Stores svgView arguments of SVG fragment identifiers.
32 class SVGView {
33  public:
34   SVGView();
35 
36   SVGAnimatedEnumeration mZoomAndPan;
37   SVGAnimatedViewBox mViewBox;
38   SVGAnimatedPreserveAspectRatio mPreserveAspectRatio;
39   UniquePtr<SVGAnimatedTransformList> mTransforms;
40 };
41 
42 class DOMSVGTranslatePoint final : public nsISVGPoint {
43  public:
DOMSVGTranslatePoint(SVGPoint * aPt,SVGSVGElement * aElement)44   DOMSVGTranslatePoint(SVGPoint* aPt, SVGSVGElement* aElement)
45       : nsISVGPoint(aPt, true), mElement(aElement) {}
46 
DOMSVGTranslatePoint(DOMSVGTranslatePoint * aPt)47   explicit DOMSVGTranslatePoint(DOMSVGTranslatePoint* aPt)
48       : nsISVGPoint(&aPt->mPt, true), mElement(aPt->mElement) {}
49 
50   NS_DECL_ISUPPORTS_INHERITED
51   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DOMSVGTranslatePoint, nsISVGPoint)
52 
53   virtual DOMSVGPoint* Copy() override;
54 
55   // WebIDL
X()56   virtual float X() override { return mPt.GetX(); }
Y()57   virtual float Y() override { return mPt.GetY(); }
58   virtual void SetX(float aValue, ErrorResult& rv) override;
59   virtual void SetY(float aValue, ErrorResult& rv) override;
60   virtual already_AddRefed<nsISVGPoint> MatrixTransform(
61       SVGMatrix& matrix) override;
62 
63   virtual nsISupports* GetParentObject() override;
64 
65   RefPtr<SVGSVGElement> mElement;
66 
67  private:
68   ~DOMSVGTranslatePoint() = default;
69 };
70 
71 typedef SVGViewportElement SVGSVGElementBase;
72 
73 class SVGSVGElement final : public SVGSVGElementBase {
74   friend class ::nsSVGOuterSVGFrame;
75   friend class mozilla::SVGFragmentIdentifier;
76   friend class mozilla::AutoSVGViewHandler;
77   friend class mozilla::AutoPreserveAspectRatioOverride;
78   friend class mozilla::dom::SVGView;
79 
80  protected:
81   SVGSVGElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
82                 FromParser aFromParser);
83   virtual JSObject* WrapNode(JSContext* aCx,
84                              JS::Handle<JSObject*> aGivenProto) override;
85 
86   friend nsresult(::NS_NewSVGSVGElement(
87       nsIContent** aResult,
88       already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
89       mozilla::dom::FromParser aFromParser));
90 
91   ~SVGSVGElement() = default;
92 
93  public:
94   // interfaces:
95   NS_DECL_ISUPPORTS_INHERITED
96   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(SVGSVGElement, SVGSVGElementBase)
97 
98   /**
99    * For use by zoom controls to allow currentScale, currentTranslate.x and
100    * currentTranslate.y to be set by a single operation that dispatches a
101    * single SVGZoom event (instead of one SVGZoom and two SVGScroll events).
102    *
103    * XXX SVGZoomEvent is no more, is this needed?
104    */
105   MOZ_CAN_RUN_SCRIPT_BOUNDARY void SetCurrentScaleTranslate(float s, float x,
106                                                             float y);
107 
108   // nsIContent interface
109   void GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
110   virtual bool IsEventAttributeNameInternal(nsAtom* aName) override;
111 
112   // nsINode methods:
113   virtual nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override;
114 
115   // WebIDL
116   already_AddRefed<DOMSVGAnimatedLength> X();
117   already_AddRefed<DOMSVGAnimatedLength> Y();
118   already_AddRefed<DOMSVGAnimatedLength> Width();
119   already_AddRefed<DOMSVGAnimatedLength> Height();
120   bool UseCurrentView();
121   float CurrentScale();
122   void SetCurrentScale(float aCurrentScale);
123   already_AddRefed<nsISVGPoint> CurrentTranslate();
124   void SetCurrentTranslate(float x, float y);
125   uint32_t SuspendRedraw(uint32_t max_wait_milliseconds);
126   void UnsuspendRedraw(uint32_t suspend_handle_id);
127   void UnsuspendRedrawAll();
128   void ForceRedraw();
129   void PauseAnimations();
130   void UnpauseAnimations();
131   bool AnimationsPaused();
132   float GetCurrentTimeAsFloat();
133   void SetCurrentTime(float seconds);
134   void DeselectAll();
135   already_AddRefed<DOMSVGNumber> CreateSVGNumber();
136   already_AddRefed<DOMSVGLength> CreateSVGLength();
137   already_AddRefed<DOMSVGAngle> CreateSVGAngle();
138   already_AddRefed<nsISVGPoint> CreateSVGPoint();
139   already_AddRefed<SVGMatrix> CreateSVGMatrix();
140   already_AddRefed<SVGRect> CreateSVGRect();
141   already_AddRefed<DOMSVGTransform> CreateSVGTransform();
142   already_AddRefed<DOMSVGTransform> CreateSVGTransformFromMatrix(
143       SVGMatrix& matrix);
144   using nsINode::GetElementById;  // This does what we want
145   uint16_t ZoomAndPan();
146   void SetZoomAndPan(uint16_t aZoomAndPan, ErrorResult& rv);
147 
148   // SVGElement overrides
149 
150   virtual nsresult BindToTree(BindContext&, nsINode& aParent) override;
151   virtual void UnbindFromTree(bool aNullParent) override;
152   virtual SVGAnimatedTransformList* GetAnimatedTransformList(
153       uint32_t aFlags = 0) override;
154 
155   // SVGSVGElement methods:
156 
157   // Returns true IFF our attributes are currently overridden by a <view>
158   // element and that element's ID matches the passed-in string.
IsOverriddenBy(const nsAString & aViewID)159   bool IsOverriddenBy(const nsAString& aViewID) const {
160     return mCurrentViewID && mCurrentViewID->Equals(aViewID);
161   }
162 
163   SMILTimeContainer* GetTimedDocumentRoot();
164 
165   // public helpers:
166 
167   /**
168    * Returns -1 if the width/height is a percentage, else returns the user unit
169    * length clamped to fit in a int32_t.
170    * XXX see bug 1112533 comment 3 - we should fix drawImage so that we can
171    * change these methods to make zero the error flag for percentages.
172    */
173   int32_t GetIntrinsicWidth();
174   int32_t GetIntrinsicHeight();
175 
176   // This services any pending notifications for the transform on on this root
177   // <svg> node needing to be recalculated.  (Only applicable in
178   // SVG-as-an-image documents.)
179   virtual void FlushImageTransformInvalidation();
180 
181  private:
182   // SVGViewportElement methods:
183 
184   virtual SVGViewElement* GetCurrentViewElement() const;
185   virtual SVGPreserveAspectRatio GetPreserveAspectRatioWithOverride()
186       const override;
187 
188   // implementation helpers:
189 
190   /*
191    * While binding to the tree we need to determine if we will be the outermost
192    * <svg> element _before_ the children are bound (as they want to know what
193    * timed document root to register with) and therefore _before_ our parent is
194    * set (both actions are performed by Element::BindToTree) so we
195    * can't use GetOwnerSVGElement() as it relies on GetParent(). This code is
196    * basically a simplified version of GetOwnerSVGElement that uses the parent
197    * parameters passed in instead.
198    *
199    * FIXME(bug 1596690): GetOwnerSVGElement() uses the flattened tree parent
200    * rather than the DOM tree parent nowadays.
201    */
202   bool WillBeOutermostSVG(nsINode& aParent) const;
203 
204   // invalidate viewbox -> viewport xform & inform frames
205   void InvalidateTransformNotifyFrame();
206 
207   // Methods for <image> elements to override my "PreserveAspectRatio" value.
208   // These are private so that only our friends
209   // (AutoPreserveAspectRatioOverride in particular) have access.
210   void SetImageOverridePreserveAspectRatio(const SVGPreserveAspectRatio& aPAR);
211   void ClearImageOverridePreserveAspectRatio();
212 
213   // Set/Clear properties to hold old version of preserveAspectRatio
214   // when it's being overridden by an <image> element that we are inside of.
215   bool SetPreserveAspectRatioProperty(const SVGPreserveAspectRatio& aPAR);
216   const SVGPreserveAspectRatio* GetPreserveAspectRatioProperty() const;
217   bool ClearPreserveAspectRatioProperty();
218 
GetCurrentTranslate()219   virtual SVGPoint GetCurrentTranslate() const override {
220     return mCurrentTranslate;
221   }
GetCurrentScale()222   virtual float GetCurrentScale() const override { return mCurrentScale; }
223 
224   virtual const SVGAnimatedViewBox& GetViewBoxInternal() const override;
225   virtual SVGAnimatedTransformList* GetTransformInternal() const override;
226 
227   virtual EnumAttributesInfo GetEnumInfo() override;
228 
229   enum { ZOOMANDPAN };
230   SVGAnimatedEnumeration mEnumAttributes[1];
231   static SVGEnumMapping sZoomAndPanMap[];
232   static EnumInfo sEnumInfo[1];
233 
234   // The time container for animations within this SVG document fragment. Set
235   // for all outermost <svg> elements (not nested <svg> elements).
236   UniquePtr<SMILTimeContainer> mTimedDocumentRoot;
237 
238   // zoom and pan
239   // IMPORTANT: see the comment in RecordCurrentScaleTranslate before writing
240   // code to change any of these!
241   SVGPoint mCurrentTranslate;
242   float mCurrentScale;
243   SVGPoint mPreviousTranslate;
244   float mPreviousScale;
245 
246   // For outermost <svg> elements created from parsing, animation is started by
247   // the onload event in accordance with the SVG spec, but for <svg> elements
248   // created by script or promoted from inner <svg> to outermost <svg> we need
249   // to manually kick off animation when they are bound to the tree.
250   bool mStartAnimationOnBindToTree;
251 
252   bool mImageNeedsTransformInvalidation;
253 
254   // mCurrentViewID and mSVGView are mutually exclusive; we can have
255   // at most one non-null.
256   UniquePtr<nsString> mCurrentViewID;
257   UniquePtr<SVGView> mSVGView;
258 };
259 
260 }  // namespace dom
261 
262 class MOZ_RAII AutoSVGTimeSetRestore {
263  public:
AutoSVGTimeSetRestore(dom::SVGSVGElement * aRootElem,float aFrameTime MOZ_GUARD_OBJECT_NOTIFIER_PARAM)264   AutoSVGTimeSetRestore(dom::SVGSVGElement* aRootElem,
265                         float aFrameTime MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
266       : mRootElem(aRootElem),
267         mOriginalTime(mRootElem->GetCurrentTimeAsFloat()) {
268     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
269     mRootElem->SetCurrentTime(
270         aFrameTime);  // Does nothing if there's no change.
271   }
272 
~AutoSVGTimeSetRestore()273   ~AutoSVGTimeSetRestore() { mRootElem->SetCurrentTime(mOriginalTime); }
274 
275  private:
276   const RefPtr<dom::SVGSVGElement> mRootElem;
277   const float mOriginalTime;
278   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
279 };
280 
281 class MOZ_RAII AutoPreserveAspectRatioOverride {
282  public:
AutoPreserveAspectRatioOverride(const Maybe<SVGImageContext> & aSVGContext,dom::SVGSVGElement * aRootElem MOZ_GUARD_OBJECT_NOTIFIER_PARAM)283   AutoPreserveAspectRatioOverride(const Maybe<SVGImageContext>& aSVGContext,
284                                   dom::SVGSVGElement* aRootElem
285                                       MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
286       : mRootElem(aRootElem), mDidOverride(false) {
287     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
288     MOZ_ASSERT(mRootElem, "No SVG/Symbol node to manage?");
289 
290     if (aSVGContext.isSome() &&
291         aSVGContext->GetPreserveAspectRatio().isSome()) {
292       // Override preserveAspectRatio in our helper document.
293       // XXXdholbert We should technically be overriding the helper doc's clip
294       // and overflow properties here, too. See bug 272288 comment 36.
295       mRootElem->SetImageOverridePreserveAspectRatio(
296           *aSVGContext->GetPreserveAspectRatio());
297       mDidOverride = true;
298     }
299   }
300 
~AutoPreserveAspectRatioOverride()301   ~AutoPreserveAspectRatioOverride() {
302     if (mDidOverride) {
303       mRootElem->ClearImageOverridePreserveAspectRatio();
304     }
305   }
306 
307  private:
308   const RefPtr<dom::SVGSVGElement> mRootElem;
309   bool mDidOverride;
310   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
311 };
312 
313 }  // namespace mozilla
314 
315 #endif  // SVGSVGElement_h
316