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/. */
7 #ifndef DOM_SVG_SVGANIMATEDLENGTH_H_
8 #define DOM_SVG_SVGANIMATEDLENGTH_H_
10 #include "mozilla/Attributes.h"
11 #include "mozilla/SMILAttr.h"
12 #include "mozilla/SVGContentUtils.h"
13 #include "mozilla/UniquePtr.h"
14 #include "mozilla/dom/SVGLengthBinding.h"
15 #include "mozilla/dom/SVGElement.h"
18 struct GeckoFontMetrics
;
21 class mozAutoDocUpdate
;
26 class AutoChangeLengthNotifier
;
30 class DOMSVGAnimatedLength
;
32 class SVGAnimationElement
;
33 class SVGViewportElement
;
35 class UserSpaceMetrics
{
37 enum class Type
: uint32_t { This
, Root
};
38 static GeckoFontMetrics
DefaultFontMetrics();
39 static GeckoFontMetrics
GetFontMetrics(const Element
* aElement
);
40 static WritingMode
GetWritingMode(const Element
* aElement
);
41 static float GetZoom(const Element
* aElement
);
42 static CSSSize
GetCSSViewportSizeFromContext(const nsPresContext
* aContext
);
44 virtual ~UserSpaceMetrics() = default;
46 virtual float GetEmLength(Type aType
) const = 0;
47 virtual float GetZoom() const = 0;
48 virtual float GetRootZoom() const = 0;
49 float GetExLength(Type aType
) const;
50 float GetChSize(Type aType
) const;
51 float GetIcWidth(Type aType
) const;
52 float GetCapHeight(Type aType
) const;
53 virtual float GetAxisLength(uint8_t aCtxType
) const = 0;
54 virtual CSSSize
GetCSSViewportSize() const = 0;
55 virtual float GetLineHeight(Type aType
) const = 0;
58 virtual GeckoFontMetrics
GetFontMetricsForType(Type aType
) const = 0;
59 virtual WritingMode
GetWritingModeForType(Type aType
) const = 0;
62 class UserSpaceMetricsWithSize
: public UserSpaceMetrics
{
64 virtual gfx::Size
GetSize() const = 0;
65 float GetAxisLength(uint8_t aCtxType
) const override
;
68 class SVGElementMetrics final
: public UserSpaceMetrics
{
70 explicit SVGElementMetrics(const SVGElement
* aSVGElement
,
71 const SVGViewportElement
* aCtx
= nullptr);
73 float GetEmLength(Type aType
) const override
{
74 return SVGContentUtils::GetFontSize(GetElementForType(aType
));
76 float GetAxisLength(uint8_t aCtxType
) const override
;
77 CSSSize
GetCSSViewportSize() const override
;
78 float GetLineHeight(Type aType
) const override
;
79 float GetZoom() const override
;
80 float GetRootZoom() const override
;
83 bool EnsureCtx() const;
84 const Element
* GetElementForType(Type aType
) const;
85 GeckoFontMetrics
GetFontMetricsForType(Type aType
) const override
;
86 WritingMode
GetWritingModeForType(Type aType
) const override
;
88 const SVGElement
* mSVGElement
;
89 mutable const SVGViewportElement
* mCtx
;
92 class NonSVGFrameUserSpaceMetrics final
: public UserSpaceMetricsWithSize
{
94 explicit NonSVGFrameUserSpaceMetrics(nsIFrame
* aFrame
);
96 float GetEmLength(Type aType
) const override
;
97 gfx::Size
GetSize() const override
;
98 CSSSize
GetCSSViewportSize() const override
;
99 float GetLineHeight(Type aType
) const override
;
100 float GetZoom() const override
;
101 float GetRootZoom() const override
;
104 GeckoFontMetrics
GetFontMetricsForType(Type aType
) const override
;
105 WritingMode
GetWritingModeForType(Type aType
) const override
;
111 class SVGAnimatedLength
{
112 friend class AutoChangeLengthNotifier
;
113 friend class dom::DOMSVGAnimatedLength
;
114 friend class dom::DOMSVGLength
;
115 using DOMSVGLength
= dom::DOMSVGLength
;
116 using SVGElement
= dom::SVGElement
;
117 using SVGViewportElement
= dom::SVGViewportElement
;
118 using UserSpaceMetrics
= dom::UserSpaceMetrics
;
121 void Init(uint8_t aCtxType
= SVGContentUtils::XY
, uint8_t aAttrEnum
= 0xff,
123 uint8_t aUnitType
= dom::SVGLength_Binding::SVG_LENGTHTYPE_NUMBER
) {
124 mAnimVal
= mBaseVal
= aValue
;
125 mBaseUnitType
= mAnimUnitType
= aUnitType
;
126 mAttrEnum
= aAttrEnum
;
132 SVGAnimatedLength
& operator=(const SVGAnimatedLength
& aLength
) {
133 mBaseVal
= aLength
.mBaseVal
;
134 mAnimVal
= aLength
.mAnimVal
;
135 mBaseUnitType
= aLength
.mBaseUnitType
;
136 mAnimUnitType
= aLength
.mAnimUnitType
;
137 mIsAnimated
= aLength
.mIsAnimated
;
138 mIsBaseSet
= aLength
.mIsBaseSet
;
142 nsresult
SetBaseValueString(const nsAString
& aValue
, SVGElement
* aSVGElement
,
144 void GetBaseValueString(nsAString
& aValue
) const;
145 void GetAnimValueString(nsAString
& aValue
) const;
147 float GetBaseValue(const SVGElement
* aSVGElement
) const {
148 return mBaseVal
* GetPixelsPerUnit(aSVGElement
, mBaseUnitType
);
151 float GetAnimValue(const SVGElement
* aSVGElement
) const {
152 return mAnimVal
* GetPixelsPerUnit(aSVGElement
, mAnimUnitType
);
154 float GetAnimValueWithZoom(const SVGElement
* aSVGElement
) const {
155 return mAnimVal
* GetPixelsPerUnitWithZoom(aSVGElement
, mAnimUnitType
);
157 float GetAnimValueWithZoom(nsIFrame
* aFrame
) const {
158 return mAnimVal
* GetPixelsPerUnitWithZoom(aFrame
, mAnimUnitType
);
160 float GetAnimValueWithZoom(const SVGViewportElement
* aCtx
) const {
161 return mAnimVal
* GetPixelsPerUnitWithZoom(aCtx
, mAnimUnitType
);
163 float GetAnimValueWithZoom(const UserSpaceMetrics
& aMetrics
) const {
164 return mAnimVal
* GetPixelsPerUnitWithZoom(aMetrics
, mAnimUnitType
);
167 uint8_t GetCtxType() const { return mCtxType
; }
168 uint8_t GetBaseUnitType() const { return mBaseUnitType
; }
169 uint8_t GetAnimUnitType() const { return mAnimUnitType
; }
170 bool IsPercentage() const {
171 return mAnimUnitType
== dom::SVGLength_Binding::SVG_LENGTHTYPE_PERCENTAGE
;
173 float GetAnimValInSpecifiedUnits() const { return mAnimVal
; }
174 float GetBaseValInSpecifiedUnits() const { return mBaseVal
; }
176 bool HasBaseVal() const { return mIsBaseSet
; }
177 // Returns true if the animated value of this length has been explicitly
178 // set (either by animation, or by taking on the base value which has been
179 // explicitly set by markup or a DOM call), false otherwise.
180 // If this returns false, the animated value is still valid, that is,
181 // usable, and represents the default base value of the attribute.
182 bool IsExplicitlySet() const { return mIsAnimated
|| mIsBaseSet
; }
184 bool IsAnimated() const { return mIsAnimated
; }
186 already_AddRefed
<dom::DOMSVGAnimatedLength
> ToDOMAnimatedLength(
187 SVGElement
* aSVGElement
);
189 UniquePtr
<SMILAttr
> ToSMILAttr(SVGElement
* aSVGElement
);
194 uint8_t mBaseUnitType
;
195 uint8_t mAnimUnitType
;
196 uint8_t mAttrEnum
: 6; // element specified tracking for attribute
197 uint8_t mCtxType
: 2; // X, Y or Unspecified
198 bool mIsAnimated
: 1;
201 // These APIs returns the number of user-unit pixels per unit of the
202 // given type, in a given context (frame/element/etc).
203 float GetPixelsPerUnit(const SVGElement
* aSVGElement
,
204 uint8_t aUnitType
) const;
205 float GetPixelsPerUnitWithZoom(nsIFrame
* aFrame
, uint8_t aUnitType
) const;
206 float GetPixelsPerUnitWithZoom(const UserSpaceMetrics
& aMetrics
,
207 uint8_t aUnitType
) const;
208 float GetPixelsPerUnitWithZoom(const SVGElement
* aSVGElement
,
209 uint8_t aUnitType
) const;
210 float GetPixelsPerUnitWithZoom(const SVGViewportElement
* aCtx
,
211 uint8_t aUnitType
) const;
213 // SetBaseValue and SetAnimValue set the value in user units. This may fail
214 // if unit conversion fails e.g. conversion to ex or em units where the
216 // SetBaseValueInSpecifiedUnits and SetAnimValueInSpecifiedUnits do not
217 // perform unit conversion and are therefore infallible.
218 nsresult
SetBaseValue(float aValue
, SVGElement
* aSVGElement
, bool aDoSetAttr
);
219 void SetBaseValueInSpecifiedUnits(float aValue
, SVGElement
* aSVGElement
,
221 void SetAnimValue(float aValue
, uint16_t aUnitType
, SVGElement
* aSVGElement
);
222 void SetAnimValueInSpecifiedUnits(float aValue
, SVGElement
* aSVGElement
);
223 nsresult
NewValueSpecifiedUnits(uint16_t aUnitType
,
224 float aValueInSpecifiedUnits
,
225 SVGElement
* aSVGElement
);
226 nsresult
ConvertToSpecifiedUnits(uint16_t aUnitType
, SVGElement
* aSVGElement
);
227 already_AddRefed
<DOMSVGLength
> ToDOMBaseVal(SVGElement
* aSVGElement
);
228 already_AddRefed
<DOMSVGLength
> ToDOMAnimVal(SVGElement
* aSVGElement
);
231 struct SMILLength
: public SMILAttr
{
233 SMILLength(SVGAnimatedLength
* aVal
, SVGElement
* aSVGElement
)
234 : mVal(aVal
), mSVGElement(aSVGElement
) {}
236 // These will stay alive because a SMILAttr only lives as long
237 // as the Compositing step, and DOM elements don't get a chance to
239 SVGAnimatedLength
* mVal
;
240 SVGElement
* mSVGElement
;
243 nsresult
ValueFromString(const nsAString
& aStr
,
244 const dom::SVGAnimationElement
* aSrcElement
,
246 bool& aPreventCachingOfSandwich
) const override
;
247 SMILValue
GetBaseValue() const override
;
248 void ClearAnimValue() override
;
249 nsresult
SetAnimValue(const SMILValue
& aValue
) override
;
254 * This class is used by the SMIL code when a length is to be stored in a
255 * SMILValue instance. Since SMILValue objects may be cached, it is necessary
256 * for us to hold a strong reference to our element so that it doesn't
257 * disappear out from under us if, say, the element is removed from the DOM
260 class SVGLengthAndInfo
{
262 SVGLengthAndInfo() = default;
264 explicit SVGLengthAndInfo(dom::SVGElement
* aElement
)
265 : mElement(do_GetWeakReference(aElement
->AsNode())) {}
267 void SetInfo(dom::SVGElement
* aElement
) {
268 mElement
= do_GetWeakReference(aElement
->AsNode());
271 dom::SVGElement
* Element() const {
272 nsCOMPtr
<nsIContent
> e
= do_QueryReferent(mElement
);
273 return static_cast<dom::SVGElement
*>(e
.get());
276 bool operator==(const SVGLengthAndInfo
& rhs
) const {
277 return mValue
== rhs
.mValue
&& mUnitType
== rhs
.mUnitType
&&
278 mCtxType
== rhs
.mCtxType
;
281 float Value() const { return mValue
; }
283 uint8_t UnitType() const { return mUnitType
; }
285 void CopyFrom(const SVGLengthAndInfo
& rhs
) {
286 mElement
= rhs
.mElement
;
288 mUnitType
= rhs
.mUnitType
;
289 mCtxType
= rhs
.mCtxType
;
292 float ConvertUnits(const SVGLengthAndInfo
& aTo
) const;
294 float ValueInPixels(const dom::UserSpaceMetrics
& aMetrics
) const;
296 void Add(const SVGLengthAndInfo
& aValueToAdd
, uint32_t aCount
);
298 static void Interpolate(const SVGLengthAndInfo
& aStart
,
299 const SVGLengthAndInfo
& aEnd
, double aUnitDistance
,
300 SVGLengthAndInfo
& aResult
);
303 * Enables SVGAnimatedLength values to be copied into SVGLengthAndInfo
304 * objects. Note that callers should also call SetInfo() when using this
307 void CopyBaseFrom(const SVGAnimatedLength
& rhs
) {
308 mValue
= rhs
.GetBaseValInSpecifiedUnits();
309 mUnitType
= rhs
.GetBaseUnitType();
310 mCtxType
= rhs
.GetCtxType();
313 void Set(float aValue
, uint8_t aUnitType
, uint8_t aCtxType
) {
315 mUnitType
= aUnitType
;
320 // We must keep a weak reference to our element because we may belong to a
321 // cached baseVal SMILValue. See the comments starting at:
322 // https://bugzilla.mozilla.org/show_bug.cgi?id=515116#c15
323 // See also https://bugzilla.mozilla.org/show_bug.cgi?id=653497
326 uint8_t mUnitType
= dom::SVGLength_Binding::SVG_LENGTHTYPE_NUMBER
;
327 uint8_t mCtxType
= SVGContentUtils::XY
;
330 } // namespace mozilla
332 #endif // DOM_SVG_SVGANIMATEDLENGTH_H_