Line data Source code
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 "nsSVGNumberPair.h"
8 : #include "nsSVGAttrTearoffTable.h"
9 : #include "nsCharSeparatedTokenizer.h"
10 : #include "nsSMILValue.h"
11 : #include "SVGContentUtils.h"
12 : #include "SVGNumberPairSMILType.h"
13 :
14 : using namespace mozilla;
15 : using namespace mozilla::dom;
16 :
17 : static nsSVGAttrTearoffTable<nsSVGNumberPair, nsSVGNumberPair::DOMAnimatedNumber>
18 3 : sSVGFirstAnimatedNumberTearoffTable;
19 : static nsSVGAttrTearoffTable<nsSVGNumberPair, nsSVGNumberPair::DOMAnimatedNumber>
20 3 : sSVGSecondAnimatedNumberTearoffTable;
21 :
22 : static nsresult
23 0 : ParseNumberOptionalNumber(const nsAString& aValue,
24 : float aValues[2])
25 : {
26 : nsCharSeparatedTokenizerTemplate<IsSVGWhitespace>
27 : tokenizer(aValue, ',',
28 0 : nsCharSeparatedTokenizer::SEPARATOR_OPTIONAL);
29 0 : if (tokenizer.whitespaceBeforeFirstToken()) {
30 0 : return NS_ERROR_DOM_SYNTAX_ERR;
31 : }
32 :
33 : uint32_t i;
34 0 : for (i = 0; i < 2 && tokenizer.hasMoreTokens(); ++i) {
35 0 : if (!SVGContentUtils::ParseNumber(tokenizer.nextToken(), aValues[i])) {
36 0 : return NS_ERROR_DOM_SYNTAX_ERR;
37 : }
38 : }
39 0 : if (i == 1) {
40 0 : aValues[1] = aValues[0];
41 : }
42 :
43 0 : if (i == 0 || // Too few values.
44 0 : tokenizer.hasMoreTokens() || // Too many values.
45 0 : tokenizer.whitespaceAfterCurrentToken() || // Trailing whitespace.
46 0 : tokenizer.separatorAfterCurrentToken()) { // Trailing comma.
47 0 : return NS_ERROR_DOM_SYNTAX_ERR;
48 : }
49 :
50 0 : return NS_OK;
51 : }
52 :
53 : nsresult
54 0 : nsSVGNumberPair::SetBaseValueString(const nsAString &aValueAsString,
55 : nsSVGElement *aSVGElement)
56 : {
57 : float val[2];
58 :
59 0 : nsresult rv = ParseNumberOptionalNumber(aValueAsString, val);
60 0 : if (NS_FAILED(rv)) {
61 0 : return rv;
62 : }
63 :
64 0 : mBaseVal[0] = val[0];
65 0 : mBaseVal[1] = val[1];
66 0 : mIsBaseSet = true;
67 0 : if (!mIsAnimated) {
68 0 : mAnimVal[0] = mBaseVal[0];
69 0 : mAnimVal[1] = mBaseVal[1];
70 : }
71 : else {
72 0 : aSVGElement->AnimationNeedsResample();
73 : }
74 :
75 : // We don't need to call Will/DidChange* here - we're only called by
76 : // nsSVGElement::ParseAttribute under Element::SetAttr,
77 : // which takes care of notifying.
78 0 : return NS_OK;
79 : }
80 :
81 : void
82 0 : nsSVGNumberPair::GetBaseValueString(nsAString &aValueAsString) const
83 : {
84 0 : aValueAsString.Truncate();
85 0 : aValueAsString.AppendFloat(mBaseVal[0]);
86 0 : if (mBaseVal[0] != mBaseVal[1]) {
87 0 : aValueAsString.AppendLiteral(", ");
88 0 : aValueAsString.AppendFloat(mBaseVal[1]);
89 : }
90 0 : }
91 :
92 : void
93 0 : nsSVGNumberPair::SetBaseValue(float aValue, PairIndex aPairIndex,
94 : nsSVGElement *aSVGElement)
95 : {
96 0 : uint32_t index = (aPairIndex == eFirst ? 0 : 1);
97 0 : if (mIsBaseSet && mBaseVal[index] == aValue) {
98 0 : return;
99 : }
100 0 : nsAttrValue emptyOrOldValue = aSVGElement->WillChangeNumberPair(mAttrEnum);
101 0 : mBaseVal[index] = aValue;
102 0 : mIsBaseSet = true;
103 0 : if (!mIsAnimated) {
104 0 : mAnimVal[index] = aValue;
105 : }
106 : else {
107 0 : aSVGElement->AnimationNeedsResample();
108 : }
109 0 : aSVGElement->DidChangeNumberPair(mAttrEnum, emptyOrOldValue);
110 : }
111 :
112 : void
113 0 : nsSVGNumberPair::SetBaseValues(float aValue1, float aValue2,
114 : nsSVGElement *aSVGElement)
115 : {
116 0 : if (mIsBaseSet && mBaseVal[0] == aValue1 && mBaseVal[1] == aValue2) {
117 0 : return;
118 : }
119 0 : nsAttrValue emptyOrOldValue = aSVGElement->WillChangeNumberPair(mAttrEnum);
120 0 : mBaseVal[0] = aValue1;
121 0 : mBaseVal[1] = aValue2;
122 0 : mIsBaseSet = true;
123 0 : if (!mIsAnimated) {
124 0 : mAnimVal[0] = aValue1;
125 0 : mAnimVal[1] = aValue2;
126 : }
127 : else {
128 0 : aSVGElement->AnimationNeedsResample();
129 : }
130 0 : aSVGElement->DidChangeNumberPair(mAttrEnum, emptyOrOldValue);
131 : }
132 :
133 : void
134 0 : nsSVGNumberPair::SetAnimValue(const float aValue[2], nsSVGElement *aSVGElement)
135 : {
136 0 : if (mIsAnimated && mAnimVal[0] == aValue[0] && mAnimVal[1] == aValue[1]) {
137 0 : return;
138 : }
139 0 : mAnimVal[0] = aValue[0];
140 0 : mAnimVal[1] = aValue[1];
141 0 : mIsAnimated = true;
142 0 : aSVGElement->DidAnimateNumberPair(mAttrEnum);
143 : }
144 :
145 : already_AddRefed<SVGAnimatedNumber>
146 0 : nsSVGNumberPair::ToDOMAnimatedNumber(PairIndex aIndex,
147 : nsSVGElement* aSVGElement)
148 : {
149 : RefPtr<DOMAnimatedNumber> domAnimatedNumber =
150 : aIndex == eFirst ? sSVGFirstAnimatedNumberTearoffTable.GetTearoff(this) :
151 0 : sSVGSecondAnimatedNumberTearoffTable.GetTearoff(this);
152 0 : if (!domAnimatedNumber) {
153 0 : domAnimatedNumber = new DOMAnimatedNumber(this, aIndex, aSVGElement);
154 0 : if (aIndex == eFirst) {
155 0 : sSVGFirstAnimatedNumberTearoffTable.AddTearoff(this, domAnimatedNumber);
156 : } else {
157 0 : sSVGSecondAnimatedNumberTearoffTable.AddTearoff(this, domAnimatedNumber);
158 : }
159 : }
160 :
161 0 : return domAnimatedNumber.forget();
162 : }
163 :
164 0 : nsSVGNumberPair::DOMAnimatedNumber::~DOMAnimatedNumber()
165 : {
166 0 : if (mIndex == eFirst) {
167 0 : sSVGFirstAnimatedNumberTearoffTable.RemoveTearoff(mVal);
168 : } else {
169 0 : sSVGSecondAnimatedNumberTearoffTable.RemoveTearoff(mVal);
170 : }
171 0 : }
172 :
173 : UniquePtr<nsISMILAttr>
174 0 : nsSVGNumberPair::ToSMILAttr(nsSVGElement *aSVGElement)
175 : {
176 0 : return MakeUnique<SMILNumberPair>(this, aSVGElement);
177 : }
178 :
179 : nsresult
180 0 : nsSVGNumberPair::SMILNumberPair::ValueFromString(const nsAString& aStr,
181 : const dom::SVGAnimationElement* /*aSrcElement*/,
182 : nsSMILValue& aValue,
183 : bool& aPreventCachingOfSandwich) const
184 : {
185 : float values[2];
186 :
187 0 : nsresult rv = ParseNumberOptionalNumber(aStr, values);
188 0 : if (NS_FAILED(rv)) {
189 0 : return rv;
190 : }
191 :
192 0 : nsSMILValue val(&SVGNumberPairSMILType::sSingleton);
193 0 : val.mU.mNumberPair[0] = values[0];
194 0 : val.mU.mNumberPair[1] = values[1];
195 0 : aValue = val;
196 0 : aPreventCachingOfSandwich = false;
197 :
198 0 : return NS_OK;
199 : }
200 :
201 : nsSMILValue
202 0 : nsSVGNumberPair::SMILNumberPair::GetBaseValue() const
203 : {
204 0 : nsSMILValue val(&SVGNumberPairSMILType::sSingleton);
205 0 : val.mU.mNumberPair[0] = mVal->mBaseVal[0];
206 0 : val.mU.mNumberPair[1] = mVal->mBaseVal[1];
207 0 : return val;
208 : }
209 :
210 : void
211 0 : nsSVGNumberPair::SMILNumberPair::ClearAnimValue()
212 : {
213 0 : if (mVal->mIsAnimated) {
214 0 : mVal->mIsAnimated = false;
215 0 : mVal->mAnimVal[0] = mVal->mBaseVal[0];
216 0 : mVal->mAnimVal[1] = mVal->mBaseVal[1];
217 0 : mSVGElement->DidAnimateNumberPair(mVal->mAttrEnum);
218 : }
219 0 : }
220 :
221 : nsresult
222 0 : nsSVGNumberPair::SMILNumberPair::SetAnimValue(const nsSMILValue& aValue)
223 : {
224 0 : NS_ASSERTION(aValue.mType == &SVGNumberPairSMILType::sSingleton,
225 : "Unexpected type to assign animated value");
226 0 : if (aValue.mType == &SVGNumberPairSMILType::sSingleton) {
227 0 : mVal->SetAnimValue(aValue.mU.mNumberPair, mSVGElement);
228 : }
229 0 : return NS_OK;
230 : }
|