SVGAnimatedLength.h (12130B)
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 DOM_SVG_SVGANIMATEDLENGTH_H_ 8 #define DOM_SVG_SVGANIMATEDLENGTH_H_ 9 10 #include "mozilla/SMILAttr.h" 11 #include "mozilla/SVGContentUtils.h" 12 #include "mozilla/UniquePtr.h" 13 #include "mozilla/dom/SVGElement.h" 14 #include "mozilla/dom/SVGLengthBinding.h" 15 #include "nsError.h" 16 17 struct GeckoFontMetrics; 18 class nsPresContext; 19 class nsFontMetrics; 20 class mozAutoDocUpdate; 21 class nsIFrame; 22 23 namespace mozilla { 24 25 class AutoChangeLengthNotifier; 26 class SMILValue; 27 28 namespace dom { 29 class DOMSVGAnimatedLength; 30 class DOMSVGLength; 31 class SVGAnimationElement; 32 class SVGViewportElement; 33 34 class UserSpaceMetrics { 35 public: 36 enum class Type : uint32_t { This, Root }; 37 static GeckoFontMetrics DefaultFontMetrics(); 38 static GeckoFontMetrics GetFontMetrics(const Element* aElement); 39 static WritingMode GetWritingMode(const Element* aElement); 40 static float GetZoom(const Element* aElement); 41 static CSSSize GetCSSViewportSizeFromContext(const nsPresContext* aContext); 42 43 virtual ~UserSpaceMetrics() = default; 44 45 virtual float GetEmLength(Type aType) const = 0; 46 virtual float GetZoom() const = 0; 47 virtual float GetRootZoom() const = 0; 48 float GetExLength(Type aType) const; 49 float GetChSize(Type aType) const; 50 float GetIcWidth(Type aType) const; 51 float GetCapHeight(Type aType) const; 52 virtual float GetAxisLength(uint8_t aCtxType) const = 0; 53 virtual CSSSize GetCSSViewportSize() const = 0; 54 virtual float GetLineHeight(Type aType) const = 0; 55 56 protected: 57 virtual GeckoFontMetrics GetFontMetricsForType(Type aType) const = 0; 58 virtual WritingMode GetWritingModeForType(Type aType) const = 0; 59 }; 60 61 class UserSpaceMetricsWithSize : public UserSpaceMetrics { 62 public: 63 virtual gfx::Size GetSize() const = 0; 64 float GetAxisLength(uint8_t aCtxType) const override; 65 }; 66 67 class SVGElementMetrics final : public UserSpaceMetrics { 68 public: 69 explicit SVGElementMetrics(const SVGElement* aSVGElement, 70 const SVGViewportElement* aCtx = nullptr); 71 72 float GetEmLength(Type aType) const override { 73 return SVGContentUtils::GetFontSize(GetElementForType(aType)); 74 } 75 float GetAxisLength(uint8_t aCtxType) const override; 76 CSSSize GetCSSViewportSize() const override; 77 float GetLineHeight(Type aType) const override; 78 float GetZoom() const override; 79 float GetRootZoom() const override; 80 81 private: 82 bool EnsureCtx() const; 83 const Element* GetElementForType(Type aType) const; 84 GeckoFontMetrics GetFontMetricsForType(Type aType) const override; 85 WritingMode GetWritingModeForType(Type aType) const override; 86 87 const SVGElement* mSVGElement; 88 mutable const SVGViewportElement* mCtx; 89 }; 90 91 class NonSVGFrameUserSpaceMetrics final : public UserSpaceMetricsWithSize { 92 public: 93 explicit NonSVGFrameUserSpaceMetrics(nsIFrame* aFrame); 94 95 float GetEmLength(Type aType) const override; 96 gfx::Size GetSize() const override; 97 CSSSize GetCSSViewportSize() const override; 98 float GetLineHeight(Type aType) const override; 99 float GetZoom() const override; 100 float GetRootZoom() const override; 101 102 private: 103 GeckoFontMetrics GetFontMetricsForType(Type aType) const override; 104 WritingMode GetWritingModeForType(Type aType) const override; 105 nsIFrame* mFrame; 106 }; 107 108 } // namespace dom 109 110 class SVGAnimatedLength { 111 friend class AutoChangeLengthNotifier; 112 friend class dom::DOMSVGAnimatedLength; 113 friend class dom::DOMSVGLength; 114 using DOMSVGLength = dom::DOMSVGLength; 115 using SVGElement = dom::SVGElement; 116 using SVGViewportElement = dom::SVGViewportElement; 117 using UserSpaceMetrics = dom::UserSpaceMetrics; 118 119 public: 120 void Init(uint8_t aCtxType = SVGContentUtils::XY, uint8_t aAttrEnum = 0xff, 121 float aValue = 0, 122 uint8_t aUnitType = dom::SVGLength_Binding::SVG_LENGTHTYPE_NUMBER) { 123 mAnimVal = mBaseVal = aValue; 124 mBaseUnitType = mAnimUnitType = aUnitType; 125 mAttrEnum = aAttrEnum; 126 mCtxType = aCtxType; 127 mIsAnimated = false; 128 mIsBaseSet = false; 129 } 130 131 SVGAnimatedLength& operator=(const SVGAnimatedLength& aLength) { 132 mBaseVal = aLength.mBaseVal; 133 mAnimVal = aLength.mAnimVal; 134 mBaseUnitType = aLength.mBaseUnitType; 135 mAnimUnitType = aLength.mAnimUnitType; 136 mIsAnimated = aLength.mIsAnimated; 137 mIsBaseSet = aLength.mIsBaseSet; 138 return *this; 139 } 140 141 nsresult SetBaseValueString(const nsAString& aValue, SVGElement* aSVGElement, 142 bool aDoSetAttr); 143 void GetBaseValueString(nsAString& aValue) const; 144 void GetAnimValueString(nsAString& aValue) const; 145 146 float GetBaseValue(const SVGElement* aSVGElement) const { 147 return mBaseVal * GetPixelsPerUnit(aSVGElement, mBaseUnitType); 148 } 149 150 float GetAnimValue(const SVGElement* aSVGElement) const { 151 return mAnimVal * GetPixelsPerUnit(aSVGElement, mAnimUnitType); 152 } 153 float GetAnimValueWithZoom(const SVGElement* aSVGElement) const { 154 return mAnimVal * GetPixelsPerUnitWithZoom(aSVGElement, mAnimUnitType); 155 } 156 float GetAnimValueWithZoom(nsIFrame* aFrame) const { 157 return mAnimVal * GetPixelsPerUnitWithZoom(aFrame, mAnimUnitType); 158 } 159 float GetAnimValueWithZoom(const SVGViewportElement* aCtx) const { 160 return mAnimVal * GetPixelsPerUnitWithZoom(aCtx, mAnimUnitType); 161 } 162 float GetAnimValueWithZoom(const UserSpaceMetrics& aMetrics) const { 163 return mAnimVal * GetPixelsPerUnitWithZoom(aMetrics, mAnimUnitType); 164 } 165 166 uint8_t GetCtxType() const { return mCtxType; } 167 uint8_t GetBaseUnitType() const { return mBaseUnitType; } 168 uint8_t GetAnimUnitType() const { return mAnimUnitType; } 169 bool IsPercentage() const { 170 return mAnimUnitType == dom::SVGLength_Binding::SVG_LENGTHTYPE_PERCENTAGE; 171 } 172 float GetAnimValInSpecifiedUnits() const { return mAnimVal; } 173 float GetBaseValInSpecifiedUnits() const { return mBaseVal; } 174 175 bool HasBaseVal() const { return mIsBaseSet; } 176 // Returns true if the animated value of this length has been explicitly 177 // set (either by animation, or by taking on the base value which has been 178 // explicitly set by markup or a DOM call), false otherwise. 179 // If this returns false, the animated value is still valid, that is, 180 // usable, and represents the default base value of the attribute. 181 bool IsExplicitlySet() const { return mIsAnimated || mIsBaseSet; } 182 183 bool IsAnimated() const { return mIsAnimated; } 184 185 already_AddRefed<dom::DOMSVGAnimatedLength> ToDOMAnimatedLength( 186 SVGElement* aSVGElement); 187 188 UniquePtr<SMILAttr> ToSMILAttr(SVGElement* aSVGElement); 189 190 private: 191 float mAnimVal; 192 float mBaseVal; 193 uint8_t mBaseUnitType; 194 uint8_t mAnimUnitType; 195 uint8_t mAttrEnum : 6; // element specified tracking for attribute 196 uint8_t mCtxType : 2; // X, Y or Unspecified 197 bool mIsAnimated : 1; 198 bool mIsBaseSet : 1; 199 200 // These APIs returns the number of user-unit pixels per unit of the 201 // given type, in a given context (frame/element/etc). 202 float GetPixelsPerUnit(const SVGElement* aSVGElement, 203 uint8_t aUnitType) const; 204 float GetPixelsPerUnitWithZoom(nsIFrame* aFrame, uint8_t aUnitType) const; 205 float GetPixelsPerUnitWithZoom(const UserSpaceMetrics& aMetrics, 206 uint8_t aUnitType) const; 207 float GetPixelsPerUnitWithZoom(const SVGElement* aSVGElement, 208 uint8_t aUnitType) const; 209 float GetPixelsPerUnitWithZoom(const SVGViewportElement* aCtx, 210 uint8_t aUnitType) const; 211 212 // SetBaseValue and SetAnimValue set the value in user units. This may fail 213 // if unit conversion fails e.g. conversion to ex or em units where the 214 // font-size is 0. 215 // SetBaseValueInSpecifiedUnits and SetAnimValueInSpecifiedUnits do not 216 // perform unit conversion and are therefore infallible. 217 nsresult SetBaseValue(float aValue, SVGElement* aSVGElement, bool aDoSetAttr); 218 void SetBaseValueInSpecifiedUnits(float aValue, SVGElement* aSVGElement, 219 bool aDoSetAttr); 220 void SetAnimValue(float aValue, uint16_t aUnitType, SVGElement* aSVGElement); 221 void SetAnimValueInSpecifiedUnits(float aValue, SVGElement* aSVGElement); 222 void NewValueSpecifiedUnits(uint16_t aUnitType, float aValueInSpecifiedUnits, 223 SVGElement* aSVGElement); 224 void ConvertToSpecifiedUnits(uint16_t aUnitType, SVGElement* aSVGElement, 225 ErrorResult& aRv); 226 already_AddRefed<DOMSVGLength> ToDOMBaseVal(SVGElement* aSVGElement); 227 already_AddRefed<DOMSVGLength> ToDOMAnimVal(SVGElement* aSVGElement); 228 229 public: 230 struct SMILLength : public SMILAttr { 231 public: 232 SMILLength(SVGAnimatedLength* aVal, SVGElement* aSVGElement) 233 : mVal(aVal), mSVGElement(aSVGElement) {} 234 235 // These will stay alive because a SMILAttr only lives as long 236 // as the Compositing step, and DOM elements don't get a chance to 237 // die during that. 238 SVGAnimatedLength* mVal; 239 SVGElement* mSVGElement; 240 241 // SMILAttr methods 242 nsresult ValueFromString(const nsAString& aStr, 243 const dom::SVGAnimationElement* aSrcElement, 244 SMILValue& aValue, 245 bool& aPreventCachingOfSandwich) const override; 246 SMILValue GetBaseValue() const override; 247 void ClearAnimValue() override; 248 nsresult SetAnimValue(const SMILValue& aValue) override; 249 }; 250 }; 251 252 /** 253 * This class is used by the SMIL code when a length is to be stored in a 254 * SMILValue instance. Since SMILValue objects may be cached, it is necessary 255 * for us to hold a strong reference to our element so that it doesn't 256 * disappear out from under us if, say, the element is removed from the DOM 257 * tree. 258 */ 259 class SVGLengthAndInfo { 260 public: 261 SVGLengthAndInfo() = default; 262 263 explicit SVGLengthAndInfo(dom::SVGElement* aElement) 264 : mElement(do_GetWeakReference(aElement->AsNode())) {} 265 266 void SetInfo(dom::SVGElement* aElement) { 267 mElement = do_GetWeakReference(aElement->AsNode()); 268 } 269 270 dom::SVGElement* Element() const { 271 nsCOMPtr<nsIContent> e = do_QueryReferent(mElement); 272 return static_cast<dom::SVGElement*>(e.get()); 273 } 274 275 bool operator==(const SVGLengthAndInfo& rhs) const { 276 return mValue == rhs.mValue && mUnitType == rhs.mUnitType && 277 mCtxType == rhs.mCtxType; 278 } 279 280 float Value() const { return mValue; } 281 282 uint8_t UnitType() const { return mUnitType; } 283 284 void CopyFrom(const SVGLengthAndInfo& rhs) { 285 mElement = rhs.mElement; 286 mValue = rhs.mValue; 287 mUnitType = rhs.mUnitType; 288 mCtxType = rhs.mCtxType; 289 } 290 291 float ConvertUnits(const SVGLengthAndInfo& aTo) const; 292 293 float ValueInPixels(const dom::UserSpaceMetrics& aMetrics) const; 294 295 void Add(const SVGLengthAndInfo& aValueToAdd, uint32_t aCount); 296 297 static void Interpolate(const SVGLengthAndInfo& aStart, 298 const SVGLengthAndInfo& aEnd, double aUnitDistance, 299 SVGLengthAndInfo& aResult); 300 301 /** 302 * Enables SVGAnimatedLength values to be copied into SVGLengthAndInfo 303 * objects. Note that callers should also call SetInfo() when using this 304 * method! 305 */ 306 void CopyBaseFrom(const SVGAnimatedLength& rhs) { 307 mValue = rhs.GetBaseValInSpecifiedUnits(); 308 mUnitType = rhs.GetBaseUnitType(); 309 mCtxType = rhs.GetCtxType(); 310 } 311 312 void Set(float aValue, uint8_t aUnitType, uint8_t aCtxType) { 313 mValue = aValue; 314 mUnitType = aUnitType; 315 mCtxType = aCtxType; 316 } 317 318 private: 319 // We must keep a weak reference to our element because we may belong to a 320 // cached baseVal SMILValue. See the comments starting at: 321 // https://bugzilla.mozilla.org/show_bug.cgi?id=515116#c15 322 // See also https://bugzilla.mozilla.org/show_bug.cgi?id=653497 323 nsWeakPtr mElement; 324 float mValue = 0.0f; 325 uint8_t mUnitType = dom::SVGLength_Binding::SVG_LENGTHTYPE_NUMBER; 326 uint8_t mCtxType = SVGContentUtils::XY; 327 }; 328 329 } // namespace mozilla 330 331 #endif // DOM_SVG_SVGANIMATEDLENGTH_H_