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 Mozilla SVG Project code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Jonathan Watt.
19 : * Portions created by the Initial Developer are Copyright (C) 2004
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Craig Topper <craig.topper@gmail.com> (original author)
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either of the GNU General Public License Version 2 or later (the "GPL"),
27 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #include "nsSVGViewBox.h"
40 : #include "nsSVGUtils.h"
41 : #include "prdtoa.h"
42 : #include "nsTextFormatter.h"
43 : #include "nsCharSeparatedTokenizer.h"
44 : #include "nsMathUtils.h"
45 : #include "nsSMILValue.h"
46 : #include "SVGViewBoxSMILType.h"
47 :
48 : #define NUM_VIEWBOX_COMPONENTS 4
49 : using namespace mozilla;
50 :
51 : /* Implementation of nsSVGViewBoxRect methods */
52 :
53 : bool
54 0 : nsSVGViewBoxRect::operator==(const nsSVGViewBoxRect& aOther) const
55 : {
56 0 : if (&aOther == this)
57 0 : return true;
58 :
59 : return x == aOther.x &&
60 : y == aOther.y &&
61 : width == aOther.width &&
62 0 : height == aOther.height;
63 : }
64 :
65 : /* Cycle collection macros for nsSVGViewBox */
66 :
67 1464 : NS_SVG_VAL_IMPL_CYCLE_COLLECTION(nsSVGViewBox::DOMBaseVal, mSVGElement)
68 1464 : NS_SVG_VAL_IMPL_CYCLE_COLLECTION(nsSVGViewBox::DOMAnimVal, mSVGElement)
69 1464 : NS_SVG_VAL_IMPL_CYCLE_COLLECTION(nsSVGViewBox::DOMAnimatedRect, mSVGElement)
70 :
71 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsSVGViewBox::DOMBaseVal)
72 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsSVGViewBox::DOMBaseVal)
73 :
74 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsSVGViewBox::DOMAnimVal)
75 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsSVGViewBox::DOMAnimVal)
76 :
77 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsSVGViewBox::DOMAnimatedRect)
78 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsSVGViewBox::DOMAnimatedRect)
79 :
80 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSVGViewBox::DOMBaseVal)
81 0 : NS_INTERFACE_MAP_ENTRY(nsIDOMSVGRect)
82 0 : NS_INTERFACE_MAP_ENTRY(nsISupports)
83 0 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGRect)
84 0 : NS_INTERFACE_MAP_END
85 :
86 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSVGViewBox::DOMAnimVal)
87 0 : NS_INTERFACE_MAP_ENTRY(nsIDOMSVGRect)
88 0 : NS_INTERFACE_MAP_ENTRY(nsISupports)
89 0 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGRect)
90 0 : NS_INTERFACE_MAP_END
91 :
92 : DOMCI_DATA(SVGAnimatedRect, nsSVGViewBox::DOMAnimatedRect)
93 :
94 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSVGViewBox::DOMAnimatedRect)
95 0 : NS_INTERFACE_MAP_ENTRY(nsIDOMSVGAnimatedRect)
96 0 : NS_INTERFACE_MAP_ENTRY(nsISupports)
97 0 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGAnimatedRect)
98 0 : NS_INTERFACE_MAP_END
99 :
100 : /* Implementation of nsSVGViewBox methods */
101 :
102 : void
103 0 : nsSVGViewBox::Init()
104 : {
105 0 : mBaseVal = nsSVGViewBoxRect();
106 0 : mAnimVal = nsnull;
107 0 : mHasBaseVal = false;
108 0 : }
109 :
110 : void
111 0 : nsSVGViewBox::SetAnimValue(float aX, float aY, float aWidth, float aHeight,
112 : nsSVGElement *aSVGElement)
113 : {
114 0 : if (!mAnimVal) {
115 : // it's okay if allocation fails - and no point in reporting that
116 0 : mAnimVal = new nsSVGViewBoxRect(aX, aY, aWidth, aHeight);
117 : } else {
118 0 : mAnimVal->x = aX;
119 0 : mAnimVal->y = aY;
120 0 : mAnimVal->width = aWidth;
121 0 : mAnimVal->height = aHeight;
122 : }
123 0 : aSVGElement->DidAnimateViewBox();
124 0 : }
125 :
126 : void
127 0 : nsSVGViewBox::SetBaseValue(float aX, float aY, float aWidth, float aHeight,
128 : nsSVGElement *aSVGElement)
129 : {
130 0 : if (mHasBaseVal && mBaseVal == nsSVGViewBoxRect(aX, aY, aWidth, aHeight)) {
131 0 : return;
132 : }
133 :
134 0 : nsAttrValue emptyOrOldValue = aSVGElement->WillChangeViewBox();
135 :
136 0 : mBaseVal = nsSVGViewBoxRect(aX, aY, aWidth, aHeight);
137 0 : mHasBaseVal = true;
138 :
139 0 : aSVGElement->DidChangeViewBox(emptyOrOldValue);
140 0 : if (mAnimVal) {
141 0 : aSVGElement->AnimationNeedsResample();
142 : }
143 : }
144 :
145 : static nsresult
146 0 : ToSVGViewBoxRect(const nsAString& aStr, nsSVGViewBoxRect *aViewBox)
147 : {
148 : nsCharSeparatedTokenizerTemplate<IsSVGWhitespace>
149 : tokenizer(aStr, ',',
150 0 : nsCharSeparatedTokenizer::SEPARATOR_OPTIONAL);
151 : float vals[NUM_VIEWBOX_COMPONENTS];
152 : PRUint32 i;
153 0 : for (i = 0; i < NUM_VIEWBOX_COMPONENTS && tokenizer.hasMoreTokens(); ++i) {
154 0 : NS_ConvertUTF16toUTF8 utf8Token(tokenizer.nextToken());
155 0 : const char *token = utf8Token.get();
156 0 : if (*token == '\0') {
157 0 : return NS_ERROR_DOM_SYNTAX_ERR; // empty string (e.g. two commas in a row)
158 : }
159 :
160 : char *end;
161 0 : vals[i] = float(PR_strtod(token, &end));
162 0 : if (*end != '\0' || !NS_finite(vals[i])) {
163 0 : return NS_ERROR_DOM_SYNTAX_ERR; // parse error
164 : }
165 : }
166 :
167 0 : if (i != NUM_VIEWBOX_COMPONENTS || // Too few values.
168 0 : tokenizer.hasMoreTokens() || // Too many values.
169 0 : tokenizer.lastTokenEndedWithSeparator()) { // Trailing comma.
170 0 : return NS_ERROR_DOM_SYNTAX_ERR;
171 : }
172 :
173 0 : aViewBox->x = vals[0];
174 0 : aViewBox->y = vals[1];
175 0 : aViewBox->width = vals[2];
176 0 : aViewBox->height = vals[3];
177 :
178 0 : return NS_OK;
179 : }
180 :
181 : nsresult
182 0 : nsSVGViewBox::SetBaseValueString(const nsAString& aValue,
183 : nsSVGElement *aSVGElement)
184 : {
185 0 : nsSVGViewBoxRect viewBox;
186 0 : nsresult res = ToSVGViewBoxRect(aValue, &viewBox);
187 0 : if (NS_SUCCEEDED(res)) {
188 0 : mBaseVal = nsSVGViewBoxRect(viewBox.x, viewBox.y, viewBox.width, viewBox.height);
189 0 : mHasBaseVal = true;
190 :
191 0 : if (mAnimVal) {
192 0 : aSVGElement->AnimationNeedsResample();
193 : }
194 : // We don't need to call Will/DidChange* here - we're only called by
195 : // nsSVGElement::ParseAttribute under nsGenericElement::SetAttr,
196 : // which takes care of notifying.
197 : }
198 0 : return res;
199 : }
200 :
201 : void
202 0 : nsSVGViewBox::GetBaseValueString(nsAString& aValue) const
203 : {
204 : PRUnichar buf[200];
205 : nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar),
206 0 : NS_LITERAL_STRING("%g %g %g %g").get(),
207 : (double)mBaseVal.x, (double)mBaseVal.y,
208 0 : (double)mBaseVal.width, (double)mBaseVal.height);
209 0 : aValue.Assign(buf);
210 0 : }
211 :
212 : nsresult
213 0 : nsSVGViewBox::ToDOMAnimatedRect(nsIDOMSVGAnimatedRect **aResult,
214 : nsSVGElement* aSVGElement)
215 : {
216 0 : *aResult = new DOMAnimatedRect(this, aSVGElement);
217 0 : NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
218 :
219 0 : NS_ADDREF(*aResult);
220 0 : return NS_OK;
221 : }
222 :
223 : NS_IMETHODIMP
224 0 : nsSVGViewBox::DOMAnimatedRect::GetBaseVal(nsIDOMSVGRect **aResult)
225 : {
226 0 : *aResult = new nsSVGViewBox::DOMBaseVal(mVal, mSVGElement);
227 0 : NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
228 :
229 0 : NS_ADDREF(*aResult);
230 0 : return NS_OK;
231 : }
232 :
233 : NS_IMETHODIMP
234 0 : nsSVGViewBox::DOMAnimatedRect::GetAnimVal(nsIDOMSVGRect **aResult)
235 : {
236 0 : *aResult = new nsSVGViewBox::DOMAnimVal(mVal, mSVGElement);
237 0 : NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
238 :
239 0 : NS_ADDREF(*aResult);
240 0 : return NS_OK;
241 : }
242 :
243 : NS_IMETHODIMP
244 0 : nsSVGViewBox::DOMBaseVal::SetX(float aX)
245 : {
246 0 : nsSVGViewBoxRect rect = mVal->GetBaseValue();
247 0 : rect.x = aX;
248 : mVal->SetBaseValue(rect.x, rect.y, rect.width, rect.height,
249 0 : mSVGElement);
250 0 : return NS_OK;
251 : }
252 :
253 : NS_IMETHODIMP
254 0 : nsSVGViewBox::DOMBaseVal::SetY(float aY)
255 : {
256 0 : nsSVGViewBoxRect rect = mVal->GetBaseValue();
257 0 : rect.y = aY;
258 : mVal->SetBaseValue(rect.x, rect.y, rect.width, rect.height,
259 0 : mSVGElement);
260 0 : return NS_OK;
261 : }
262 :
263 : NS_IMETHODIMP
264 0 : nsSVGViewBox::DOMBaseVal::SetWidth(float aWidth)
265 : {
266 0 : nsSVGViewBoxRect rect = mVal->GetBaseValue();
267 0 : rect.width = aWidth;
268 : mVal->SetBaseValue(rect.x, rect.y, rect.width, rect.height,
269 0 : mSVGElement);
270 0 : return NS_OK;
271 : }
272 :
273 : NS_IMETHODIMP
274 0 : nsSVGViewBox::DOMBaseVal::SetHeight(float aHeight)
275 : {
276 0 : nsSVGViewBoxRect rect = mVal->GetBaseValue();
277 0 : rect.height = aHeight;
278 : mVal->SetBaseValue(rect.x, rect.y, rect.width, rect.height,
279 0 : mSVGElement);
280 0 : return NS_OK;
281 : }
282 :
283 : nsISMILAttr*
284 0 : nsSVGViewBox::ToSMILAttr(nsSVGElement *aSVGElement)
285 : {
286 0 : return new SMILViewBox(this, aSVGElement);
287 : }
288 :
289 : nsresult
290 0 : nsSVGViewBox::SMILViewBox
291 : ::ValueFromString(const nsAString& aStr,
292 : const nsISMILAnimationElement* /*aSrcElement*/,
293 : nsSMILValue& aValue,
294 : bool& aPreventCachingOfSandwich) const
295 : {
296 0 : nsSVGViewBoxRect viewBox;
297 0 : nsresult res = ToSVGViewBoxRect(aStr, &viewBox);
298 0 : if (NS_FAILED(res)) {
299 0 : return res;
300 : }
301 0 : nsSMILValue val(&SVGViewBoxSMILType::sSingleton);
302 0 : *static_cast<nsSVGViewBoxRect*>(val.mU.mPtr) = viewBox;
303 0 : aValue.Swap(val);
304 0 : aPreventCachingOfSandwich = false;
305 :
306 0 : return NS_OK;
307 : }
308 :
309 : nsSMILValue
310 0 : nsSVGViewBox::SMILViewBox::GetBaseValue() const
311 : {
312 0 : nsSMILValue val(&SVGViewBoxSMILType::sSingleton);
313 0 : *static_cast<nsSVGViewBoxRect*>(val.mU.mPtr) = mVal->mBaseVal;
314 : return val;
315 : }
316 :
317 : void
318 0 : nsSVGViewBox::SMILViewBox::ClearAnimValue()
319 : {
320 0 : if (mVal->mAnimVal) {
321 0 : mVal->mAnimVal = nsnull;
322 0 : mSVGElement->DidAnimateViewBox();
323 : }
324 0 : }
325 :
326 : nsresult
327 0 : nsSVGViewBox::SMILViewBox::SetAnimValue(const nsSMILValue& aValue)
328 : {
329 0 : NS_ASSERTION(aValue.mType == &SVGViewBoxSMILType::sSingleton,
330 : "Unexpected type to assign animated value");
331 0 : if (aValue.mType == &SVGViewBoxSMILType::sSingleton) {
332 0 : nsSVGViewBoxRect &vb = *static_cast<nsSVGViewBoxRect*>(aValue.mU.mPtr);
333 0 : mVal->SetAnimValue(vb.x, vb.y, vb.width, vb.height, mSVGElement);
334 : }
335 0 : return NS_OK;
336 4392 : }
|