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