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 : * Jonathan Watt <jonathan.watt@strath.ac.uk> (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 "mozilla/Util.h"
40 :
41 : #include "SVGAnimatedPreserveAspectRatio.h"
42 : #include "nsWhitespaceTokenizer.h"
43 : #include "nsSMILValue.h"
44 : #include "SMILEnumType.h"
45 :
46 : using namespace mozilla;
47 :
48 : ////////////////////////////////////////////////////////////////////////
49 : // SVGAnimatedPreserveAspectRatio class
50 :
51 1464 : NS_SVG_VAL_IMPL_CYCLE_COLLECTION(
52 : SVGAnimatedPreserveAspectRatio::DOMBaseVal, mSVGElement)
53 1464 : NS_SVG_VAL_IMPL_CYCLE_COLLECTION(
54 : SVGAnimatedPreserveAspectRatio::DOMAnimVal, mSVGElement)
55 1464 : NS_SVG_VAL_IMPL_CYCLE_COLLECTION(
56 : SVGAnimatedPreserveAspectRatio::DOMAnimPAspectRatio, mSVGElement)
57 :
58 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(SVGAnimatedPreserveAspectRatio::DOMBaseVal)
59 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(SVGAnimatedPreserveAspectRatio::DOMBaseVal)
60 :
61 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(SVGAnimatedPreserveAspectRatio::DOMAnimVal)
62 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(SVGAnimatedPreserveAspectRatio::DOMAnimVal)
63 :
64 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(
65 : SVGAnimatedPreserveAspectRatio::DOMAnimPAspectRatio)
66 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(
67 : SVGAnimatedPreserveAspectRatio::DOMAnimPAspectRatio)
68 :
69 : DOMCI_DATA(SVGPreserveAspectRatio, SVGAnimatedPreserveAspectRatio::DOMBaseVal)
70 : DOMCI_DATA(SVGAnimatedPreserveAspectRatio,
71 : SVGAnimatedPreserveAspectRatio::DOMAnimPAspectRatio)
72 :
73 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
74 : SVGAnimatedPreserveAspectRatio::DOMBaseVal)
75 0 : NS_INTERFACE_MAP_ENTRY(nsIDOMSVGPreserveAspectRatio)
76 0 : NS_INTERFACE_MAP_ENTRY(nsISupports)
77 0 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGPreserveAspectRatio)
78 0 : NS_INTERFACE_MAP_END
79 :
80 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
81 : SVGAnimatedPreserveAspectRatio::DOMAnimVal)
82 0 : NS_INTERFACE_MAP_ENTRY(nsIDOMSVGPreserveAspectRatio)
83 0 : NS_INTERFACE_MAP_ENTRY(nsISupports)
84 0 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGPreserveAspectRatio)
85 0 : NS_INTERFACE_MAP_END
86 :
87 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
88 : SVGAnimatedPreserveAspectRatio::DOMAnimPAspectRatio)
89 0 : NS_INTERFACE_MAP_ENTRY(nsIDOMSVGAnimatedPreserveAspectRatio)
90 0 : NS_INTERFACE_MAP_ENTRY(nsISupports)
91 0 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGAnimatedPreserveAspectRatio)
92 0 : NS_INTERFACE_MAP_END
93 :
94 : /* Implementation */
95 :
96 : static const char *sAlignStrings[] =
97 : { "none", "xMinYMin", "xMidYMin", "xMaxYMin", "xMinYMid", "xMidYMid",
98 : "xMaxYMid", "xMinYMax", "xMidYMax", "xMaxYMax" };
99 :
100 : static const char *sMeetOrSliceStrings[] = { "meet", "slice" };
101 :
102 : static PRUint16
103 0 : GetAlignForString(const nsAString &aAlignString)
104 : {
105 0 : for (PRUint32 i = 0 ; i < ArrayLength(sAlignStrings) ; i++) {
106 0 : if (aAlignString.EqualsASCII(sAlignStrings[i])) {
107 0 : return (i + nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE);
108 : }
109 : }
110 :
111 0 : return nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_UNKNOWN;
112 : }
113 :
114 : static void
115 0 : GetAlignString(nsAString& aAlignString, PRUint16 aAlign)
116 : {
117 0 : NS_ASSERTION(
118 : aAlign >= nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE &&
119 : aAlign <= nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX,
120 : "Unknown align");
121 :
122 : aAlignString.AssignASCII(
123 : sAlignStrings[aAlign -
124 0 : nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE]);
125 0 : }
126 :
127 : static PRUint16
128 0 : GetMeetOrSliceForString(const nsAString &aMeetOrSlice)
129 : {
130 0 : for (PRUint32 i = 0 ; i < ArrayLength(sMeetOrSliceStrings) ; i++) {
131 0 : if (aMeetOrSlice.EqualsASCII(sMeetOrSliceStrings[i])) {
132 0 : return (i + nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_MEET);
133 : }
134 : }
135 :
136 0 : return nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_UNKNOWN;
137 : }
138 :
139 : static void
140 0 : GetMeetOrSliceString(nsAString& aMeetOrSliceString, PRUint16 aMeetOrSlice)
141 : {
142 0 : NS_ASSERTION(
143 : aMeetOrSlice >= nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_MEET &&
144 : aMeetOrSlice <= nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_SLICE,
145 : "Unknown meetOrSlice");
146 :
147 : aMeetOrSliceString.AssignASCII(
148 : sMeetOrSliceStrings[aMeetOrSlice -
149 0 : nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_MEET]);
150 0 : }
151 :
152 : nsresult
153 0 : SVGAnimatedPreserveAspectRatio::ToDOMBaseVal(
154 : nsIDOMSVGPreserveAspectRatio **aResult,
155 : nsSVGElement *aSVGElement)
156 : {
157 0 : *aResult = new DOMBaseVal(this, aSVGElement);
158 0 : if (!*aResult)
159 0 : return NS_ERROR_OUT_OF_MEMORY;
160 :
161 0 : NS_ADDREF(*aResult);
162 0 : return NS_OK;
163 : }
164 :
165 : nsresult
166 0 : SVGAnimatedPreserveAspectRatio::ToDOMAnimVal(
167 : nsIDOMSVGPreserveAspectRatio **aResult,
168 : nsSVGElement *aSVGElement)
169 : {
170 0 : *aResult = new DOMAnimVal(this, aSVGElement);
171 0 : if (!*aResult)
172 0 : return NS_ERROR_OUT_OF_MEMORY;
173 :
174 0 : NS_ADDREF(*aResult);
175 0 : return NS_OK;
176 : }
177 :
178 : static nsresult
179 0 : ToPreserveAspectRatio(const nsAString &aString,
180 : SVGPreserveAspectRatio *aValue)
181 : {
182 0 : if (aString.IsEmpty() || NS_IsAsciiWhitespace(aString[0])) {
183 0 : return NS_ERROR_DOM_SYNTAX_ERR;
184 : }
185 :
186 0 : nsWhitespaceTokenizer tokenizer(aString);
187 0 : if (!tokenizer.hasMoreTokens()) {
188 0 : return NS_ERROR_DOM_SYNTAX_ERR;
189 : }
190 0 : const nsAString &token = tokenizer.nextToken();
191 :
192 : nsresult rv;
193 0 : SVGPreserveAspectRatio val;
194 :
195 0 : val.SetDefer(token.EqualsLiteral("defer"));
196 :
197 0 : if (val.GetDefer()) {
198 0 : if (!tokenizer.hasMoreTokens()) {
199 0 : return NS_ERROR_DOM_SYNTAX_ERR;
200 : }
201 0 : rv = val.SetAlign(GetAlignForString(tokenizer.nextToken()));
202 : } else {
203 0 : rv = val.SetAlign(GetAlignForString(token));
204 : }
205 :
206 0 : if (NS_FAILED(rv)) {
207 0 : return NS_ERROR_DOM_SYNTAX_ERR;
208 : }
209 :
210 0 : if (tokenizer.hasMoreTokens()) {
211 0 : rv = val.SetMeetOrSlice(GetMeetOrSliceForString(tokenizer.nextToken()));
212 0 : if (NS_FAILED(rv)) {
213 0 : return NS_ERROR_DOM_SYNTAX_ERR;
214 : }
215 : } else {
216 0 : val.SetMeetOrSlice(nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_MEET);
217 : }
218 :
219 0 : if (tokenizer.hasMoreTokens()) {
220 0 : return NS_ERROR_DOM_SYNTAX_ERR;
221 : }
222 :
223 0 : *aValue = val;
224 0 : return NS_OK;
225 : }
226 :
227 : nsresult
228 0 : SVGAnimatedPreserveAspectRatio::SetBaseValueString(
229 : const nsAString &aValueAsString, nsSVGElement *aSVGElement)
230 : {
231 0 : SVGPreserveAspectRatio val;
232 0 : nsresult res = ToPreserveAspectRatio(aValueAsString, &val);
233 0 : if (NS_FAILED(res)) {
234 0 : return res;
235 : }
236 :
237 0 : mBaseVal = val;
238 0 : mIsBaseSet = true;
239 0 : if (!mIsAnimated) {
240 0 : mAnimVal = mBaseVal;
241 : }
242 : else {
243 0 : aSVGElement->AnimationNeedsResample();
244 : }
245 :
246 : // We don't need to call DidChange* here - we're only called by
247 : // nsSVGElement::ParseAttribute under nsGenericElement::SetAttr,
248 : // which takes care of notifying.
249 0 : return NS_OK;
250 : }
251 :
252 : void
253 0 : SVGAnimatedPreserveAspectRatio::GetBaseValueString(
254 : nsAString& aValueAsString) const
255 : {
256 0 : nsAutoString tmpString;
257 :
258 0 : aValueAsString.Truncate();
259 :
260 0 : if (mBaseVal.mDefer) {
261 0 : aValueAsString.AppendLiteral("defer ");
262 : }
263 :
264 0 : GetAlignString(tmpString, mBaseVal.mAlign);
265 0 : aValueAsString.Append(tmpString);
266 :
267 0 : if (mBaseVal.mAlign !=
268 : nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE) {
269 :
270 0 : aValueAsString.AppendLiteral(" ");
271 0 : GetMeetOrSliceString(tmpString, mBaseVal.mMeetOrSlice);
272 0 : aValueAsString.Append(tmpString);
273 : }
274 0 : }
275 :
276 : nsresult
277 0 : SVGAnimatedPreserveAspectRatio::SetBaseAlign(PRUint16 aAlign,
278 : nsSVGElement *aSVGElement)
279 : {
280 0 : if (mIsBaseSet && mBaseVal.GetAlign() == aAlign) {
281 0 : return NS_OK;
282 : }
283 :
284 0 : nsAttrValue emptyOrOldValue = aSVGElement->WillChangePreserveAspectRatio();
285 0 : nsresult rv = mBaseVal.SetAlign(aAlign);
286 0 : NS_ENSURE_SUCCESS(rv, rv);
287 0 : mIsBaseSet = true;
288 :
289 0 : mAnimVal.mAlign = mBaseVal.mAlign;
290 0 : aSVGElement->DidChangePreserveAspectRatio(emptyOrOldValue);
291 0 : if (mIsAnimated) {
292 0 : aSVGElement->AnimationNeedsResample();
293 : }
294 :
295 0 : return NS_OK;
296 : }
297 :
298 : nsresult
299 0 : SVGAnimatedPreserveAspectRatio::SetBaseMeetOrSlice(PRUint16 aMeetOrSlice,
300 : nsSVGElement *aSVGElement)
301 : {
302 0 : if (mIsBaseSet && mBaseVal.GetMeetOrSlice() == aMeetOrSlice) {
303 0 : return NS_OK;
304 : }
305 :
306 0 : nsAttrValue emptyOrOldValue = aSVGElement->WillChangePreserveAspectRatio();
307 0 : nsresult rv = mBaseVal.SetMeetOrSlice(aMeetOrSlice);
308 0 : NS_ENSURE_SUCCESS(rv, rv);
309 0 : mIsBaseSet = true;
310 :
311 0 : mAnimVal.mMeetOrSlice = mBaseVal.mMeetOrSlice;
312 0 : aSVGElement->DidChangePreserveAspectRatio(emptyOrOldValue);
313 0 : if (mIsAnimated) {
314 0 : aSVGElement->AnimationNeedsResample();
315 : }
316 :
317 0 : return NS_OK;
318 : }
319 :
320 : void
321 0 : SVGAnimatedPreserveAspectRatio::SetAnimValue(PRUint64 aPackedValue,
322 : nsSVGElement *aSVGElement)
323 : {
324 0 : mAnimVal.SetDefer(((aPackedValue & 0xff0000) >> 16) ? true : false);
325 0 : mAnimVal.SetAlign(PRUint16((aPackedValue & 0xff00) >> 8));
326 0 : mAnimVal.SetMeetOrSlice(PRUint16(aPackedValue & 0xff));
327 0 : mIsAnimated = true;
328 0 : aSVGElement->DidAnimatePreserveAspectRatio();
329 0 : }
330 :
331 : nsresult
332 0 : SVGAnimatedPreserveAspectRatio::ToDOMAnimatedPreserveAspectRatio(
333 : nsIDOMSVGAnimatedPreserveAspectRatio **aResult,
334 : nsSVGElement *aSVGElement)
335 : {
336 0 : *aResult = new DOMAnimPAspectRatio(this, aSVGElement);
337 0 : if (!*aResult)
338 0 : return NS_ERROR_OUT_OF_MEMORY;
339 :
340 0 : NS_ADDREF(*aResult);
341 0 : return NS_OK;
342 : }
343 :
344 : nsISMILAttr*
345 0 : SVGAnimatedPreserveAspectRatio::ToSMILAttr(nsSVGElement *aSVGElement)
346 : {
347 0 : return new SMILPreserveAspectRatio(this, aSVGElement);
348 : }
349 :
350 : static PRUint64
351 0 : PackPreserveAspectRatio(const SVGPreserveAspectRatio& par)
352 : {
353 : // All preserveAspectRatio values are enum values (do not interpolate), so we
354 : // can safely collate them and treat them as a single enum as for SMIL.
355 0 : PRUint64 packed = 0;
356 0 : packed |= PRUint64(par.GetDefer() ? 1 : 0) << 16;
357 0 : packed |= PRUint64(par.GetAlign()) << 8;
358 0 : packed |= PRUint64(par.GetMeetOrSlice());
359 0 : return packed;
360 : }
361 :
362 : // typedef for inner class, to make function signatures shorter below:
363 : typedef SVGAnimatedPreserveAspectRatio::SMILPreserveAspectRatio
364 : SMILPreserveAspectRatio;
365 :
366 : nsresult
367 0 : SMILPreserveAspectRatio::ValueFromString(const nsAString& aStr,
368 : const nsISMILAnimationElement* /*aSrcElement*/,
369 : nsSMILValue& aValue,
370 : bool& aPreventCachingOfSandwich) const
371 : {
372 0 : SVGPreserveAspectRatio par;
373 0 : nsresult res = ToPreserveAspectRatio(aStr, &par);
374 0 : NS_ENSURE_SUCCESS(res, res);
375 :
376 0 : nsSMILValue val(&SMILEnumType::sSingleton);
377 0 : val.mU.mUint = PackPreserveAspectRatio(par);
378 0 : aValue = val;
379 0 : aPreventCachingOfSandwich = false;
380 0 : return NS_OK;
381 : }
382 :
383 : nsSMILValue
384 0 : SMILPreserveAspectRatio::GetBaseValue() const
385 : {
386 0 : nsSMILValue val(&SMILEnumType::sSingleton);
387 0 : val.mU.mUint = PackPreserveAspectRatio(mVal->GetBaseValue());
388 : return val;
389 : }
390 :
391 : void
392 0 : SMILPreserveAspectRatio::ClearAnimValue()
393 : {
394 0 : if (mVal->mIsAnimated) {
395 0 : mVal->mIsAnimated = false;
396 0 : mVal->mAnimVal = mVal->mBaseVal;
397 0 : mSVGElement->DidAnimatePreserveAspectRatio();
398 : }
399 0 : }
400 :
401 : nsresult
402 0 : SMILPreserveAspectRatio::SetAnimValue(const nsSMILValue& aValue)
403 : {
404 0 : NS_ASSERTION(aValue.mType == &SMILEnumType::sSingleton,
405 : "Unexpected type to assign animated value");
406 0 : if (aValue.mType == &SMILEnumType::sSingleton) {
407 0 : mVal->SetAnimValue(aValue.mU.mUint, mSVGElement);
408 : }
409 0 : return NS_OK;
410 4392 : }
|