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 #include "SVGAnimatedNumber.h"
8
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"
15
16 using namespace mozilla::dom;
17
18 namespace mozilla {
19
20 /* Implementation */
21
22 static SVGAttrTearoffTable<SVGAnimatedNumber,
23 SVGAnimatedNumber::DOMAnimatedNumber>
24 sSVGAnimatedNumberTearoffTable;
25
GetValueFromString(const nsAString & aString,bool aPercentagesAllowed,float & aValue)26 static bool GetValueFromString(const nsAString& aString,
27 bool aPercentagesAllowed, float& aValue) {
28 bool success;
29 auto token = SVGContentUtils::GetAndEnsureOneToken(aString, success);
30
31 if (!success) {
32 return false;
33 }
34
35 RangedPtr<const char16_t> iter = SVGContentUtils::GetStartRangedPtr(token);
36 const RangedPtr<const char16_t> end = SVGContentUtils::GetEndRangedPtr(token);
37
38 if (!SVGContentUtils::ParseNumber(iter, end, aValue)) {
39 return false;
40 }
41
42 if (aPercentagesAllowed) {
43 const nsAString& units = Substring(iter.get(), end.get());
44 if (units.EqualsLiteral("%")) {
45 aValue /= 100;
46 return true;
47 }
48 }
49
50 return iter == end;
51 }
52
SetBaseValueString(const nsAString & aValueAsString,SVGElement * aSVGElement)53 nsresult SVGAnimatedNumber::SetBaseValueString(const nsAString& aValueAsString,
54 SVGElement* aSVGElement) {
55 float val;
56
57 if (!GetValueFromString(aValueAsString,
58 aSVGElement->NumberAttrAllowsPercentage(mAttrEnum),
59 val)) {
60 return NS_ERROR_DOM_SYNTAX_ERR;
61 }
62
63 mBaseVal = val;
64 mIsBaseSet = true;
65 if (!mIsAnimated) {
66 mAnimVal = mBaseVal;
67 } else {
68 aSVGElement->AnimationNeedsResample();
69 }
70
71 // We don't need to call DidChange* here - we're only called by
72 // SVGElement::ParseAttribute under Element::SetAttr,
73 // which takes care of notifying.
74 return NS_OK;
75 }
76
GetBaseValueString(nsAString & aValueAsString)77 void SVGAnimatedNumber::GetBaseValueString(nsAString& aValueAsString) {
78 aValueAsString.Truncate();
79 aValueAsString.AppendFloat(mBaseVal);
80 }
81
SetBaseValue(float aValue,SVGElement * aSVGElement)82 void SVGAnimatedNumber::SetBaseValue(float aValue, SVGElement* aSVGElement) {
83 if (mIsBaseSet && aValue == mBaseVal) {
84 return;
85 }
86
87 mBaseVal = aValue;
88 mIsBaseSet = true;
89 if (!mIsAnimated) {
90 mAnimVal = mBaseVal;
91 } else {
92 aSVGElement->AnimationNeedsResample();
93 }
94 aSVGElement->DidChangeNumber(mAttrEnum);
95 }
96
SetAnimValue(float aValue,SVGElement * aSVGElement)97 void SVGAnimatedNumber::SetAnimValue(float aValue, SVGElement* aSVGElement) {
98 if (mIsAnimated && aValue == mAnimVal) {
99 return;
100 }
101 mAnimVal = aValue;
102 mIsAnimated = true;
103 aSVGElement->DidAnimateNumber(mAttrEnum);
104 }
105
ToDOMAnimatedNumber(SVGElement * aSVGElement)106 already_AddRefed<DOMSVGAnimatedNumber> SVGAnimatedNumber::ToDOMAnimatedNumber(
107 SVGElement* aSVGElement) {
108 RefPtr<DOMAnimatedNumber> domAnimatedNumber =
109 sSVGAnimatedNumberTearoffTable.GetTearoff(this);
110 if (!domAnimatedNumber) {
111 domAnimatedNumber = new DOMAnimatedNumber(this, aSVGElement);
112 sSVGAnimatedNumberTearoffTable.AddTearoff(this, domAnimatedNumber);
113 }
114
115 return domAnimatedNumber.forget();
116 }
117
~DOMAnimatedNumber()118 SVGAnimatedNumber::DOMAnimatedNumber::~DOMAnimatedNumber() {
119 sSVGAnimatedNumberTearoffTable.RemoveTearoff(mVal);
120 }
121
ToSMILAttr(SVGElement * aSVGElement)122 UniquePtr<SMILAttr> SVGAnimatedNumber::ToSMILAttr(SVGElement* aSVGElement) {
123 return MakeUnique<SMILNumber>(this, aSVGElement);
124 }
125
ValueFromString(const nsAString & aStr,const mozilla::dom::SVGAnimationElement *,SMILValue & aValue,bool & aPreventCachingOfSandwich) const126 nsresult SVGAnimatedNumber::SMILNumber::ValueFromString(
127 const nsAString& aStr,
128 const mozilla::dom::SVGAnimationElement* /*aSrcElement*/, SMILValue& aValue,
129 bool& aPreventCachingOfSandwich) const {
130 float value;
131
132 if (!GetValueFromString(
133 aStr, mSVGElement->NumberAttrAllowsPercentage(mVal->mAttrEnum),
134 value)) {
135 return NS_ERROR_DOM_SYNTAX_ERR;
136 }
137
138 SMILValue val(SMILFloatType::Singleton());
139 val.mU.mDouble = value;
140 aValue = val;
141 aPreventCachingOfSandwich = false;
142
143 return NS_OK;
144 }
145
GetBaseValue() const146 SMILValue SVGAnimatedNumber::SMILNumber::GetBaseValue() const {
147 SMILValue val(SMILFloatType::Singleton());
148 val.mU.mDouble = mVal->mBaseVal;
149 return val;
150 }
151
ClearAnimValue()152 void SVGAnimatedNumber::SMILNumber::ClearAnimValue() {
153 if (mVal->mIsAnimated) {
154 mVal->mIsAnimated = false;
155 mVal->mAnimVal = mVal->mBaseVal;
156 mSVGElement->DidAnimateNumber(mVal->mAttrEnum);
157 }
158 }
159
SetAnimValue(const SMILValue & aValue)160 nsresult SVGAnimatedNumber::SMILNumber::SetAnimValue(const SMILValue& aValue) {
161 NS_ASSERTION(aValue.mType == SMILFloatType::Singleton(),
162 "Unexpected type to assign animated value");
163 if (aValue.mType == SMILFloatType::Singleton()) {
164 mVal->SetAnimValue(float(aValue.mU.mDouble), mSVGElement);
165 }
166 return NS_OK;
167 }
168
169 } // namespace mozilla
170