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 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 RangedPtr
<const char16_t
> iter
= SVGContentUtils::GetStartRangedPtr(token
);
59 const RangedPtr
<const char16_t
> end
= SVGContentUtils::GetEndRangedPtr(token
);
61 if (!SVGContentUtils::ParseNumber(iter
, end
, aValue
)) {
65 if (aPercentagesAllowed
) {
66 const nsAString
& units
= Substring(iter
.get(), end
.get());
67 if (units
.EqualsLiteral("%")) {
76 nsresult
SVGAnimatedNumber::SetBaseValueString(const nsAString
& aValueAsString
,
77 SVGElement
* aSVGElement
) {
80 if (!GetValueFromString(aValueAsString
,
81 aSVGElement
->NumberAttrAllowsPercentage(mAttrEnum
),
83 return NS_ERROR_DOM_SYNTAX_ERR
;
91 aSVGElement
->AnimationNeedsResample();
94 // We don't need to call DidChange* here - we're only called by
95 // SVGElement::ParseAttribute under Element::SetAttr,
96 // which takes care of notifying.
100 void SVGAnimatedNumber::GetBaseValueString(nsAString
& aValueAsString
) {
101 aValueAsString
.Truncate();
102 aValueAsString
.AppendFloat(mBaseVal
);
105 void SVGAnimatedNumber::SetBaseValue(float aValue
, SVGElement
* aSVGElement
) {
106 if (mIsBaseSet
&& aValue
== mBaseVal
) {
110 AutoChangeNumberNotifier
notifier(this, aSVGElement
);
119 void SVGAnimatedNumber::SetAnimValue(float aValue
, SVGElement
* aSVGElement
) {
120 if (mIsAnimated
&& aValue
== mAnimVal
) {
125 aSVGElement
->DidAnimateNumber(mAttrEnum
);
128 already_AddRefed
<DOMSVGAnimatedNumber
> SVGAnimatedNumber::ToDOMAnimatedNumber(
129 SVGElement
* aSVGElement
) {
130 RefPtr
<DOMAnimatedNumber
> domAnimatedNumber
=
131 sSVGAnimatedNumberTearoffTable
.GetTearoff(this);
132 if (!domAnimatedNumber
) {
133 domAnimatedNumber
= new DOMAnimatedNumber(this, aSVGElement
);
134 sSVGAnimatedNumberTearoffTable
.AddTearoff(this, domAnimatedNumber
);
137 return domAnimatedNumber
.forget();
140 SVGAnimatedNumber::DOMAnimatedNumber::~DOMAnimatedNumber() {
141 sSVGAnimatedNumberTearoffTable
.RemoveTearoff(mVal
);
144 UniquePtr
<SMILAttr
> SVGAnimatedNumber::ToSMILAttr(SVGElement
* aSVGElement
) {
145 return MakeUnique
<SMILNumber
>(this, aSVGElement
);
148 nsresult
SVGAnimatedNumber::SMILNumber::ValueFromString(
149 const nsAString
& aStr
,
150 const mozilla::dom::SVGAnimationElement
* /*aSrcElement*/, SMILValue
& aValue
,
151 bool& aPreventCachingOfSandwich
) const {
154 if (!GetValueFromString(
155 aStr
, mSVGElement
->NumberAttrAllowsPercentage(mVal
->mAttrEnum
),
157 return NS_ERROR_DOM_SYNTAX_ERR
;
160 SMILValue
val(SMILFloatType::Singleton());
161 val
.mU
.mDouble
= value
;
167 SMILValue
SVGAnimatedNumber::SMILNumber::GetBaseValue() const {
168 SMILValue
val(SMILFloatType::Singleton());
169 val
.mU
.mDouble
= mVal
->mBaseVal
;
173 void SVGAnimatedNumber::SMILNumber::ClearAnimValue() {
174 if (mVal
->mIsAnimated
) {
175 mVal
->mIsAnimated
= false;
176 mVal
->mAnimVal
= mVal
->mBaseVal
;
177 mSVGElement
->DidAnimateNumber(mVal
->mAttrEnum
);
181 nsresult
SVGAnimatedNumber::SMILNumber::SetAnimValue(const SMILValue
& aValue
) {
182 NS_ASSERTION(aValue
.mType
== SMILFloatType::Singleton(),
183 "Unexpected type to assign animated value");
184 if (aValue
.mType
== SMILFloatType::Singleton()) {
185 mVal
->SetAnimValue(float(aValue
.mU
.mDouble
), mSVGElement
);
190 } // namespace mozilla