1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is the Mozilla SVG project.
16 : *
17 : * The Initial Developer of the Original Code is Robert Longson.
18 : * Portions created by the Initial Developer are Copyright (C) 2011
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : *
23 : * Alternatively, the contents of this file may be used under the terms of
24 : * either the GNU General Public License Version 2 or later (the "GPL"), or
25 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 : * in which case the provisions of the GPL or the LGPL are applicable instead
27 : * of those above. If you wish to allow use of your version of this file only
28 : * under the terms of either the GPL or the LGPL, and not to allow others to
29 : * use your version of this file under the terms of the MPL, indicate your
30 : * decision by deleting the provisions above and replace them with the notice
31 : * and other provisions required by the GPL or the LGPL. If you do not delete
32 : * the provisions above, a recipient may use your version of this file under
33 : * the terms of any one of the MPL, the GPL or the LGPL.
34 : *
35 : * ***** END LICENSE BLOCK ***** */
36 :
37 : #include "nsSVGIntegerPair.h"
38 : #include "nsSVGUtils.h"
39 : #include "nsCharSeparatedTokenizer.h"
40 : #include "nsDOMError.h"
41 : #include "nsMathUtils.h"
42 : #include "nsSMILValue.h"
43 : #include "SVGIntegerPairSMILType.h"
44 :
45 : using namespace mozilla;
46 :
47 1464 : NS_SVG_VAL_IMPL_CYCLE_COLLECTION(nsSVGIntegerPair::DOMAnimatedInteger, mSVGElement)
48 :
49 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsSVGIntegerPair::DOMAnimatedInteger)
50 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsSVGIntegerPair::DOMAnimatedInteger)
51 :
52 : DOMCI_DATA(SVGAnimatedIntegerPair, nsSVGIntegerPair::DOMAnimatedInteger)
53 :
54 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSVGIntegerPair::DOMAnimatedInteger)
55 0 : NS_INTERFACE_MAP_ENTRY(nsIDOMSVGAnimatedInteger)
56 0 : NS_INTERFACE_MAP_ENTRY(nsISupports)
57 0 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGAnimatedInteger)
58 0 : NS_INTERFACE_MAP_END
59 :
60 : /* Implementation */
61 :
62 : static nsresult
63 0 : ParseIntegerOptionalInteger(const nsAString& aValue,
64 : PRInt32 aValues[2])
65 : {
66 : nsCharSeparatedTokenizerTemplate<IsSVGWhitespace>
67 : tokenizer(aValue, ',',
68 0 : nsCharSeparatedTokenizer::SEPARATOR_OPTIONAL);
69 0 : if (tokenizer.firstTokenBeganWithWhitespace()) {
70 0 : return NS_ERROR_DOM_SYNTAX_ERR;
71 : }
72 :
73 : PRUint32 i;
74 0 : for (i = 0; i < 2 && tokenizer.hasMoreTokens(); ++i) {
75 0 : NS_ConvertUTF16toUTF8 utf8Token(tokenizer.nextToken());
76 0 : const char *token = utf8Token.get();
77 0 : if (*token == '\0') {
78 0 : return NS_ERROR_DOM_SYNTAX_ERR; // empty string (e.g. two commas in a row)
79 : }
80 :
81 : char *end;
82 0 : aValues[i] = strtol(token, &end, 10);
83 0 : if (*end != '\0' || !NS_finite(aValues[i])) {
84 0 : return NS_ERROR_DOM_SYNTAX_ERR; // parse error
85 : }
86 : }
87 0 : if (i == 1) {
88 0 : aValues[1] = aValues[0];
89 : }
90 :
91 0 : if (i == 0 || // Too few values.
92 0 : tokenizer.hasMoreTokens() || // Too many values.
93 0 : tokenizer.lastTokenEndedWithWhitespace() || // Trailing whitespace.
94 0 : tokenizer.lastTokenEndedWithSeparator()) { // Trailing comma.
95 0 : return NS_ERROR_DOM_SYNTAX_ERR;
96 : }
97 :
98 0 : return NS_OK;
99 : }
100 :
101 : nsresult
102 0 : nsSVGIntegerPair::SetBaseValueString(const nsAString &aValueAsString,
103 : nsSVGElement *aSVGElement)
104 : {
105 : PRInt32 val[2];
106 :
107 0 : nsresult rv = ParseIntegerOptionalInteger(aValueAsString, val);
108 :
109 0 : if (NS_FAILED(rv)) {
110 0 : return rv;
111 : }
112 :
113 0 : mBaseVal[0] = val[0];
114 0 : mBaseVal[1] = val[1];
115 0 : mIsBaseSet = true;
116 0 : if (!mIsAnimated) {
117 0 : mAnimVal[0] = mBaseVal[0];
118 0 : mAnimVal[1] = mBaseVal[1];
119 : }
120 : else {
121 0 : aSVGElement->AnimationNeedsResample();
122 : }
123 :
124 : // We don't need to call DidChange* here - we're only called by
125 : // nsSVGElement::ParseAttribute under nsGenericElement::SetAttr,
126 : // which takes care of notifying.
127 0 : return NS_OK;
128 : }
129 :
130 : void
131 0 : nsSVGIntegerPair::GetBaseValueString(nsAString &aValueAsString) const
132 : {
133 0 : aValueAsString.Truncate();
134 0 : aValueAsString.AppendInt(mBaseVal[0]);
135 0 : if (mBaseVal[0] != mBaseVal[1]) {
136 0 : aValueAsString.AppendLiteral(", ");
137 0 : aValueAsString.AppendInt(mBaseVal[1]);
138 : }
139 0 : }
140 :
141 : void
142 0 : nsSVGIntegerPair::SetBaseValue(PRInt32 aValue, PairIndex aPairIndex,
143 : nsSVGElement *aSVGElement)
144 : {
145 0 : PRUint32 index = (aPairIndex == eFirst ? 0 : 1);
146 0 : if (mIsBaseSet && mBaseVal[index] == aValue) {
147 0 : return;
148 : }
149 :
150 0 : nsAttrValue emptyOrOldValue = aSVGElement->WillChangeIntegerPair(mAttrEnum);
151 0 : mBaseVal[index] = aValue;
152 0 : mIsBaseSet = true;
153 0 : if (!mIsAnimated) {
154 0 : mAnimVal[index] = aValue;
155 : }
156 : else {
157 0 : aSVGElement->AnimationNeedsResample();
158 : }
159 0 : aSVGElement->DidChangeIntegerPair(mAttrEnum, emptyOrOldValue);
160 : }
161 :
162 : void
163 0 : nsSVGIntegerPair::SetBaseValues(PRInt32 aValue1, PRInt32 aValue2,
164 : nsSVGElement *aSVGElement)
165 : {
166 0 : if (mIsBaseSet && mBaseVal[0] == aValue1 && mBaseVal[1] == aValue2) {
167 0 : return;
168 : }
169 :
170 0 : nsAttrValue emptyOrOldValue = aSVGElement->WillChangeIntegerPair(mAttrEnum);
171 0 : mBaseVal[0] = aValue1;
172 0 : mBaseVal[1] = aValue2;
173 0 : mIsBaseSet = true;
174 0 : if (!mIsAnimated) {
175 0 : mAnimVal[0] = aValue1;
176 0 : mAnimVal[1] = aValue2;
177 : }
178 : else {
179 0 : aSVGElement->AnimationNeedsResample();
180 : }
181 0 : aSVGElement->DidChangeIntegerPair(mAttrEnum, emptyOrOldValue);
182 : }
183 :
184 : void
185 0 : nsSVGIntegerPair::SetAnimValue(const PRInt32 aValue[2], nsSVGElement *aSVGElement)
186 : {
187 0 : mAnimVal[0] = aValue[0];
188 0 : mAnimVal[1] = aValue[1];
189 0 : mIsAnimated = true;
190 0 : aSVGElement->DidAnimateIntegerPair(mAttrEnum);
191 0 : }
192 :
193 : nsresult
194 0 : nsSVGIntegerPair::ToDOMAnimatedInteger(nsIDOMSVGAnimatedInteger **aResult,
195 : PairIndex aIndex,
196 : nsSVGElement *aSVGElement)
197 : {
198 0 : *aResult = new DOMAnimatedInteger(this, aIndex, aSVGElement);
199 0 : NS_ADDREF(*aResult);
200 0 : return NS_OK;
201 : }
202 :
203 : nsISMILAttr*
204 0 : nsSVGIntegerPair::ToSMILAttr(nsSVGElement *aSVGElement)
205 : {
206 0 : return new SMILIntegerPair(this, aSVGElement);
207 : }
208 :
209 : nsresult
210 0 : nsSVGIntegerPair::SMILIntegerPair::ValueFromString(const nsAString& aStr,
211 : const nsISMILAnimationElement* /*aSrcElement*/,
212 : nsSMILValue& aValue,
213 : bool& aPreventCachingOfSandwich) const
214 : {
215 : PRInt32 values[2];
216 :
217 0 : nsresult rv = ParseIntegerOptionalInteger(aStr, values);
218 0 : if (NS_FAILED(rv)) {
219 0 : return rv;
220 : }
221 :
222 0 : nsSMILValue val(&SVGIntegerPairSMILType::sSingleton);
223 0 : val.mU.mIntPair[0] = values[0];
224 0 : val.mU.mIntPair[1] = values[1];
225 0 : aValue = val;
226 0 : aPreventCachingOfSandwich = false;
227 :
228 0 : return NS_OK;
229 : }
230 :
231 : nsSMILValue
232 0 : nsSVGIntegerPair::SMILIntegerPair::GetBaseValue() const
233 : {
234 0 : nsSMILValue val(&SVGIntegerPairSMILType::sSingleton);
235 0 : val.mU.mIntPair[0] = mVal->mBaseVal[0];
236 0 : val.mU.mIntPair[1] = mVal->mBaseVal[1];
237 : return val;
238 : }
239 :
240 : void
241 0 : nsSVGIntegerPair::SMILIntegerPair::ClearAnimValue()
242 : {
243 0 : if (mVal->mIsAnimated) {
244 0 : mVal->mIsAnimated = false;
245 0 : mVal->mAnimVal[0] = mVal->mBaseVal[0];
246 0 : mVal->mAnimVal[1] = mVal->mBaseVal[1];
247 0 : mSVGElement->DidAnimateIntegerPair(mVal->mAttrEnum);
248 : }
249 0 : }
250 :
251 : nsresult
252 0 : nsSVGIntegerPair::SMILIntegerPair::SetAnimValue(const nsSMILValue& aValue)
253 : {
254 0 : NS_ASSERTION(aValue.mType == &SVGIntegerPairSMILType::sSingleton,
255 : "Unexpected type to assign animated value");
256 0 : if (aValue.mType == &SVGIntegerPairSMILType::sSingleton) {
257 0 : mVal->SetAnimValue(aValue.mU.mIntPair, mSVGElement);
258 : }
259 0 : return NS_OK;
260 4392 : }
|