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 #include "SVGAnimatedNumber.h"
9 #include "mozilla/Attributes.h"
10 #include "mozilla/SMILValue.h"
11 #include "mozilla/SVGContentUtils.h"
12 #include "nsContentUtils.h"
13 #include "SMILFloatType.h"
14 #include "SVGAttrTearoffTable.h"
16 using namespace mozilla::dom
;
22 //----------------------------------------------------------------------
23 // Helper class: AutoChangeNumberNotifier
24 // Stack-based helper class to ensure DidChangeNumber is called.
25 class MOZ_RAII AutoChangeNumberNotifier
{
27 AutoChangeNumberNotifier(SVGAnimatedNumber
* aNumber
, SVGElement
* aSVGElement
)
28 : mNumber(aNumber
), mSVGElement(aSVGElement
) {
29 MOZ_ASSERT(mNumber
, "Expecting non-null number");
30 MOZ_ASSERT(mSVGElement
, "Expecting non-null element");
33 ~AutoChangeNumberNotifier() {
34 mSVGElement
->DidChangeNumber(mNumber
->mAttrEnum
);
35 if (mNumber
->mIsAnimated
) {
36 mSVGElement
->AnimationNeedsResample();
41 SVGAnimatedNumber
* const mNumber
;
42 SVGElement
* const mSVGElement
;
45 MOZ_CONSTINIT
static SVGAttrTearoffTable
<SVGAnimatedNumber
,
46 SVGAnimatedNumber::DOMAnimatedNumber
>
47 sSVGAnimatedNumberTearoffTable
;
49 static bool GetValueFromString(const nsAString
& aString
,
50 bool aPercentagesAllowed
, float& aValue
) {
52 auto token
= SVGContentUtils::GetAndEnsureOneToken(aString
, success
);
58 nsAString::const_iterator iter
, end
;
59 token
.BeginReading(iter
);
60 token
.EndReading(end
);
62 if (!SVGContentUtils::ParseNumber(iter
, end
, aValue
)) {
66 if (aPercentagesAllowed
) {
67 const nsAString
& units
= Substring(iter
, end
);
68 if (units
.EqualsLiteral("%")) {
77 nsresult
SVGAnimatedNumber::SetBaseValueString(const nsAString
& aValueAsString
,
78 SVGElement
* aSVGElement
) {
81 if (!GetValueFromString(aValueAsString
,
82 aSVGElement
->NumberAttrAllowsPercentage(mAttrEnum
),
84 return NS_ERROR_DOM_SYNTAX_ERR
;
92 aSVGElement
->AnimationNeedsResample();
95 // We don't need to call DidChange* here - we're only called by
96 // SVGElement::ParseAttribute under Element::SetAttr,
97 // which takes care of notifying.
101 void SVGAnimatedNumber::GetBaseValueString(nsAString
& aValueAsString
) {
102 aValueAsString
.Truncate();
103 aValueAsString
.AppendFloat(mBaseVal
);
106 void SVGAnimatedNumber::SetBaseValue(float aValue
, SVGElement
* aSVGElement
) {
107 if (mIsBaseSet
&& aValue
== mBaseVal
) {
111 AutoChangeNumberNotifier
notifier(this, aSVGElement
);
120 void SVGAnimatedNumber::SetAnimValue(float aValue
, SVGElement
* aSVGElement
) {
121 if (mIsAnimated
&& aValue
== mAnimVal
) {
126 aSVGElement
->DidAnimateNumber(mAttrEnum
);
129 already_AddRefed
<DOMSVGAnimatedNumber
> SVGAnimatedNumber::ToDOMAnimatedNumber(
130 SVGElement
* aSVGElement
) {
131 RefPtr
<DOMAnimatedNumber
> domAnimatedNumber
=
132 sSVGAnimatedNumberTearoffTable
.GetTearoff(this);
133 if (!domAnimatedNumber
) {
134 domAnimatedNumber
= new DOMAnimatedNumber(this, aSVGElement
);
135 sSVGAnimatedNumberTearoffTable
.AddTearoff(this, domAnimatedNumber
);
138 return domAnimatedNumber
.forget();
141 SVGAnimatedNumber::DOMAnimatedNumber::~DOMAnimatedNumber() {
142 sSVGAnimatedNumberTearoffTable
.RemoveTearoff(mVal
);
145 UniquePtr
<SMILAttr
> SVGAnimatedNumber::ToSMILAttr(SVGElement
* aSVGElement
) {
146 return MakeUnique
<SMILNumber
>(this, aSVGElement
);
149 nsresult
SVGAnimatedNumber::SMILNumber::ValueFromString(
150 const nsAString
& aStr
,
151 const mozilla::dom::SVGAnimationElement
* /*aSrcElement*/, SMILValue
& aValue
,
152 bool& aPreventCachingOfSandwich
) const {
155 if (!GetValueFromString(
156 aStr
, mSVGElement
->NumberAttrAllowsPercentage(mVal
->mAttrEnum
),
158 return NS_ERROR_DOM_SYNTAX_ERR
;
161 SMILValue
val(SMILFloatType::Singleton());
162 val
.mU
.mDouble
= value
;
168 SMILValue
SVGAnimatedNumber::SMILNumber::GetBaseValue() const {
169 SMILValue
val(SMILFloatType::Singleton());
170 val
.mU
.mDouble
= mVal
->mBaseVal
;
174 void SVGAnimatedNumber::SMILNumber::ClearAnimValue() {
175 if (mVal
->mIsAnimated
) {
176 mVal
->mIsAnimated
= false;
177 mVal
->mAnimVal
= mVal
->mBaseVal
;
178 mSVGElement
->DidAnimateNumber(mVal
->mAttrEnum
);
182 nsresult
SVGAnimatedNumber::SMILNumber::SetAnimValue(const SMILValue
& aValue
) {
183 NS_ASSERTION(aValue
.mType
== SMILFloatType::Singleton(),
184 "Unexpected type to assign animated value");
185 if (aValue
.mType
== SMILFloatType::Singleton()) {
186 mVal
->SetAnimValue(float(aValue
.mU
.mDouble
), mSVGElement
);
191 } // namespace mozilla