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