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 Communicator client code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Alex Fritze <alex.fritze@crocodile-clips.com>
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 "nsSVGElement.h"
40 :
41 : #include "mozilla/Util.h"
42 :
43 : #include "nsSVGSVGElement.h"
44 : #include "nsIDocument.h"
45 : #include "nsRange.h"
46 : #include "nsIDOMAttr.h"
47 : #include "nsIDOMEventTarget.h"
48 : #include "nsIDOMMutationEvent.h"
49 : #include "nsMutationEvent.h"
50 : #include "nsXBLPrototypeBinding.h"
51 : #include "nsBindingManager.h"
52 : #include "nsXBLBinding.h"
53 : #include "nsStyleConsts.h"
54 : #include "nsDOMError.h"
55 : #include "nsIPresShell.h"
56 : #include "nsIServiceManager.h"
57 : #include "nsIXBLService.h"
58 : #include "nsGkAtoms.h"
59 : #include "mozilla/css/StyleRule.h"
60 : #include "nsRuleWalker.h"
61 : #include "mozilla/css/Declaration.h"
62 : #include "nsCSSProps.h"
63 : #include "nsCSSParser.h"
64 : #include "nsGenericHTMLElement.h"
65 : #include "nsNodeInfoManager.h"
66 : #include "nsIScriptGlobalObject.h"
67 : #include "nsEventListenerManager.h"
68 : #include "nsSVGUtils.h"
69 : #include "nsSVGLength2.h"
70 : #include "nsSVGNumber2.h"
71 : #include "nsSVGNumberPair.h"
72 : #include "nsSVGInteger.h"
73 : #include "nsSVGIntegerPair.h"
74 : #include "nsSVGAngle.h"
75 : #include "nsSVGBoolean.h"
76 : #include "nsSVGEnum.h"
77 : #include "nsSVGViewBox.h"
78 : #include "nsSVGString.h"
79 : #include "SVGAnimatedNumberList.h"
80 : #include "SVGAnimatedLengthList.h"
81 : #include "SVGAnimatedPointList.h"
82 : #include "SVGAnimatedPathSegList.h"
83 : #include "SVGAnimatedTransformList.h"
84 : #include "DOMSVGTests.h"
85 : #include "nsIDOMSVGUnitTypes.h"
86 : #include "nsSVGRect.h"
87 : #include "nsIFrame.h"
88 : #include "prdtoa.h"
89 : #include <stdarg.h>
90 : #include "nsSMILMappedAttribute.h"
91 : #include "SVGMotionSMILAttr.h"
92 : #include "nsAttrValueOrString.h"
93 :
94 : using namespace mozilla;
95 :
96 : // This is needed to ensure correct handling of calls to the
97 : // vararg-list methods in this file:
98 : // nsSVGElement::GetAnimated{Length,Number,Integer}Values
99 : // See bug 547964 for details:
100 : PR_STATIC_ASSERT(sizeof(void*) == sizeof(nsnull));
101 :
102 :
103 : nsSVGEnumMapping nsSVGElement::sSVGUnitTypesMap[] = {
104 : {&nsGkAtoms::userSpaceOnUse, nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE},
105 : {&nsGkAtoms::objectBoundingBox, nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX},
106 : {nsnull, 0}
107 : };
108 :
109 0 : nsSVGElement::nsSVGElement(already_AddRefed<nsINodeInfo> aNodeInfo)
110 0 : : nsSVGElementBase(aNodeInfo)
111 : {
112 0 : }
113 :
114 : nsresult
115 0 : nsSVGElement::Init()
116 : {
117 : // Set up length attributes - can't do this in the constructor
118 : // because we can't do a virtual call at that point
119 :
120 0 : LengthAttributesInfo lengthInfo = GetLengthInfo();
121 :
122 : PRUint32 i;
123 0 : for (i = 0; i < lengthInfo.mLengthCount; i++) {
124 0 : lengthInfo.Reset(i);
125 : }
126 :
127 0 : NumberAttributesInfo numberInfo = GetNumberInfo();
128 :
129 0 : for (i = 0; i < numberInfo.mNumberCount; i++) {
130 0 : numberInfo.Reset(i);
131 : }
132 :
133 0 : NumberPairAttributesInfo numberPairInfo = GetNumberPairInfo();
134 :
135 0 : for (i = 0; i < numberPairInfo.mNumberPairCount; i++) {
136 0 : numberPairInfo.Reset(i);
137 : }
138 :
139 0 : IntegerAttributesInfo integerInfo = GetIntegerInfo();
140 :
141 0 : for (i = 0; i < integerInfo.mIntegerCount; i++) {
142 0 : integerInfo.Reset(i);
143 : }
144 :
145 0 : IntegerPairAttributesInfo integerPairInfo = GetIntegerPairInfo();
146 :
147 0 : for (i = 0; i < integerPairInfo.mIntegerPairCount; i++) {
148 0 : integerPairInfo.Reset(i);
149 : }
150 :
151 0 : AngleAttributesInfo angleInfo = GetAngleInfo();
152 :
153 0 : for (i = 0; i < angleInfo.mAngleCount; i++) {
154 0 : angleInfo.Reset(i);
155 : }
156 :
157 0 : BooleanAttributesInfo booleanInfo = GetBooleanInfo();
158 :
159 0 : for (i = 0; i < booleanInfo.mBooleanCount; i++) {
160 0 : booleanInfo.Reset(i);
161 : }
162 :
163 0 : EnumAttributesInfo enumInfo = GetEnumInfo();
164 :
165 0 : for (i = 0; i < enumInfo.mEnumCount; i++) {
166 0 : enumInfo.Reset(i);
167 : }
168 :
169 0 : nsSVGViewBox *viewBox = GetViewBox();
170 :
171 0 : if (viewBox) {
172 0 : viewBox->Init();
173 : }
174 :
175 : SVGAnimatedPreserveAspectRatio *preserveAspectRatio =
176 0 : GetPreserveAspectRatio();
177 :
178 0 : if (preserveAspectRatio) {
179 0 : preserveAspectRatio->Init();
180 : }
181 :
182 0 : LengthListAttributesInfo lengthListInfo = GetLengthListInfo();
183 :
184 0 : for (i = 0; i < lengthListInfo.mLengthListCount; i++) {
185 0 : lengthListInfo.Reset(i);
186 : }
187 :
188 0 : NumberListAttributesInfo numberListInfo = GetNumberListInfo();
189 :
190 0 : for (i = 0; i < numberListInfo.mNumberListCount; i++) {
191 0 : numberListInfo.Reset(i);
192 : }
193 :
194 : // No need to reset SVGPointList since the default value is always the same
195 : // (an empty list).
196 :
197 : // No need to reset SVGPathData since the default value is always the same
198 : // (an empty list).
199 :
200 0 : StringAttributesInfo stringInfo = GetStringInfo();
201 :
202 0 : for (i = 0; i < stringInfo.mStringCount; i++) {
203 0 : stringInfo.Reset(i);
204 : }
205 :
206 0 : return NS_OK;
207 : }
208 :
209 : //----------------------------------------------------------------------
210 : // nsISupports methods
211 :
212 0 : NS_IMPL_ADDREF_INHERITED(nsSVGElement, nsSVGElementBase)
213 0 : NS_IMPL_RELEASE_INHERITED(nsSVGElement, nsSVGElementBase)
214 :
215 0 : NS_INTERFACE_MAP_BEGIN(nsSVGElement)
216 : // provided by nsGenericElement:
217 : // NS_INTERFACE_MAP_ENTRY(nsIContent)
218 0 : NS_INTERFACE_MAP_END_INHERITING(nsSVGElementBase)
219 :
220 : //----------------------------------------------------------------------
221 : // Implementation
222 :
223 : //----------------------------------------------------------------------
224 : // nsIContent methods
225 :
226 : nsresult
227 0 : nsSVGElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
228 : nsIContent* aBindingParent,
229 : bool aCompileEventHandlers)
230 : {
231 : nsresult rv = nsSVGElementBase::BindToTree(aDocument, aParent,
232 : aBindingParent,
233 0 : aCompileEventHandlers);
234 0 : NS_ENSURE_SUCCESS(rv, rv);
235 :
236 0 : if (!MayHaveStyle()) {
237 0 : return NS_OK;
238 : }
239 0 : const nsAttrValue* oldVal = mAttrsAndChildren.GetAttr(nsGkAtoms::style);
240 :
241 0 : if (oldVal && oldVal->Type() == nsAttrValue::eCSSStyleRule) {
242 : // we need to force a reparse because the baseURI of the document
243 : // may have changed, and in particular because we may be clones of
244 : // XBL anonymous content now being bound to the document we should
245 : // render in and due to the hacky way in which we implement the
246 : // interaction of XBL and SVG resources. Once we have a sane
247 : // ownerDocument on XBL anonymous content, this can all go away.
248 0 : nsAttrValue attrValue;
249 0 : nsAutoString stringValue;
250 0 : oldVal->ToString(stringValue);
251 : // Force in data doc, since we already have a style rule
252 0 : ParseStyleAttribute(stringValue, attrValue, true);
253 : // Don't bother going through SetInlineStyleRule, we don't want to fire off
254 : // mutation events or document notifications anyway
255 0 : rv = mAttrsAndChildren.SetAndTakeAttr(nsGkAtoms::style, attrValue);
256 0 : NS_ENSURE_SUCCESS(rv, rv);
257 : }
258 :
259 0 : return NS_OK;
260 : }
261 :
262 : nsresult
263 0 : nsSVGElement::AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
264 : const nsAttrValue* aValue, bool aNotify)
265 : {
266 : // We don't currently use nsMappedAttributes within SVG. If this changes, we
267 : // need to be very careful because some nsAttrValues used by SVG point to
268 : // member data of SVG elements and if an nsAttrValue outlives the SVG element
269 : // whose data it points to (by virtue of being stored in
270 : // mAttrsAndChildren->mMappedAttributes, meaning it's shared between
271 : // elements), the pointer will dangle. See bug 724680.
272 0 : NS_ABORT_IF_FALSE(!mAttrsAndChildren.HasMappedAttrs(),
273 : "Unexpected use of nsMappedAttributes within SVG");
274 :
275 : // If this is an svg presentation attribute we need to map it into
276 : // the content stylerule.
277 : // XXX For some reason incremental mapping doesn't work, so for now
278 : // just delete the style rule and lazily reconstruct it in
279 : // GetContentStyleRule()
280 0 : if (aNamespaceID == kNameSpaceID_None && IsAttributeMapped(aName)) {
281 0 : mContentStyleRule = nsnull;
282 : }
283 :
284 0 : if (IsEventName(aName) && aValue) {
285 0 : NS_ABORT_IF_FALSE(aValue->Type() == nsAttrValue::eString,
286 : "Expected string value for script body");
287 : nsresult rv = AddScriptEventListener(GetEventNameForAttr(aName),
288 0 : aValue->GetStringValue());
289 0 : NS_ENSURE_SUCCESS(rv, rv);
290 : }
291 :
292 0 : return nsSVGElementBase::AfterSetAttr(aNamespaceID, aName, aValue, aNotify);
293 : }
294 :
295 : bool
296 0 : nsSVGElement::ParseAttribute(PRInt32 aNamespaceID,
297 : nsIAtom* aAttribute,
298 : const nsAString& aValue,
299 : nsAttrValue& aResult)
300 : {
301 0 : nsresult rv = NS_OK;
302 0 : bool foundMatch = false;
303 0 : bool didSetResult = false;
304 :
305 0 : if (aNamespaceID == kNameSpaceID_None) {
306 :
307 : // Check for nsSVGLength2 attribute
308 0 : LengthAttributesInfo lengthInfo = GetLengthInfo();
309 :
310 : PRUint32 i;
311 0 : for (i = 0; i < lengthInfo.mLengthCount; i++) {
312 0 : if (aAttribute == *lengthInfo.mLengthInfo[i].mName) {
313 0 : rv = lengthInfo.mLengths[i].SetBaseValueString(aValue, this, false);
314 0 : if (NS_FAILED(rv)) {
315 0 : lengthInfo.Reset(i);
316 : } else {
317 0 : aResult.SetTo(lengthInfo.mLengths[i], &aValue);
318 0 : didSetResult = true;
319 : }
320 0 : foundMatch = true;
321 0 : break;
322 : }
323 : }
324 :
325 0 : if (!foundMatch) {
326 : // Check for SVGAnimatedLengthList attribute
327 0 : LengthListAttributesInfo lengthListInfo = GetLengthListInfo();
328 0 : for (i = 0; i < lengthListInfo.mLengthListCount; i++) {
329 0 : if (aAttribute == *lengthListInfo.mLengthListInfo[i].mName) {
330 0 : rv = lengthListInfo.mLengthLists[i].SetBaseValueString(aValue);
331 0 : if (NS_FAILED(rv)) {
332 0 : lengthListInfo.Reset(i);
333 : } else {
334 0 : aResult.SetTo(lengthListInfo.mLengthLists[i].GetBaseValue(),
335 0 : &aValue);
336 0 : didSetResult = true;
337 : }
338 0 : foundMatch = true;
339 0 : break;
340 : }
341 : }
342 : }
343 :
344 0 : if (!foundMatch) {
345 : // Check for SVGAnimatedNumberList attribute
346 0 : NumberListAttributesInfo numberListInfo = GetNumberListInfo();
347 0 : for (i = 0; i < numberListInfo.mNumberListCount; i++) {
348 0 : if (aAttribute == *numberListInfo.mNumberListInfo[i].mName) {
349 0 : rv = numberListInfo.mNumberLists[i].SetBaseValueString(aValue);
350 0 : if (NS_FAILED(rv)) {
351 0 : numberListInfo.Reset(i);
352 : } else {
353 0 : aResult.SetTo(numberListInfo.mNumberLists[i].GetBaseValue(),
354 0 : &aValue);
355 0 : didSetResult = true;
356 : }
357 0 : foundMatch = true;
358 0 : break;
359 : }
360 : }
361 : }
362 :
363 0 : if (!foundMatch) {
364 : // Check for SVGAnimatedPointList attribute
365 0 : if (GetPointListAttrName() == aAttribute) {
366 0 : SVGAnimatedPointList* pointList = GetAnimatedPointList();
367 0 : if (pointList) {
368 0 : pointList->SetBaseValueString(aValue);
369 : // The spec says we parse everything up to the failure, so we DON'T
370 : // need to check the result of SetBaseValueString or call
371 : // pointList->ClearBaseValue() if it fails
372 0 : aResult.SetTo(pointList->GetBaseValue(), &aValue);
373 0 : didSetResult = true;
374 0 : foundMatch = true;
375 : }
376 : }
377 : }
378 :
379 0 : if (!foundMatch) {
380 : // Check for SVGAnimatedPathSegList attribute
381 0 : if (GetPathDataAttrName() == aAttribute) {
382 0 : SVGAnimatedPathSegList* segList = GetAnimPathSegList();
383 0 : if (segList) {
384 0 : segList->SetBaseValueString(aValue);
385 : // The spec says we parse everything up to the failure, so we DON'T
386 : // need to check the result of SetBaseValueString or call
387 : // segList->ClearBaseValue() if it fails
388 0 : aResult.SetTo(segList->GetBaseValue(), &aValue);
389 0 : didSetResult = true;
390 0 : foundMatch = true;
391 : }
392 : }
393 : }
394 :
395 0 : if (!foundMatch) {
396 : // Check for nsSVGNumber2 attribute
397 0 : NumberAttributesInfo numberInfo = GetNumberInfo();
398 0 : for (i = 0; i < numberInfo.mNumberCount; i++) {
399 0 : if (aAttribute == *numberInfo.mNumberInfo[i].mName) {
400 0 : rv = numberInfo.mNumbers[i].SetBaseValueString(aValue, this);
401 0 : if (NS_FAILED(rv)) {
402 0 : numberInfo.Reset(i);
403 : } else {
404 0 : aResult.SetTo(numberInfo.mNumbers[i].GetBaseValue(), &aValue);
405 0 : didSetResult = true;
406 : }
407 0 : foundMatch = true;
408 0 : break;
409 : }
410 : }
411 : }
412 :
413 0 : if (!foundMatch) {
414 : // Check for nsSVGNumberPair attribute
415 0 : NumberPairAttributesInfo numberPairInfo = GetNumberPairInfo();
416 0 : for (i = 0; i < numberPairInfo.mNumberPairCount; i++) {
417 0 : if (aAttribute == *numberPairInfo.mNumberPairInfo[i].mName) {
418 0 : rv = numberPairInfo.mNumberPairs[i].SetBaseValueString(aValue, this);
419 0 : if (NS_FAILED(rv)) {
420 0 : numberPairInfo.Reset(i);
421 : } else {
422 0 : aResult.SetTo(numberPairInfo.mNumberPairs[i], &aValue);
423 0 : didSetResult = true;
424 : }
425 0 : foundMatch = true;
426 0 : break;
427 : }
428 : }
429 : }
430 :
431 0 : if (!foundMatch) {
432 : // Check for nsSVGInteger attribute
433 0 : IntegerAttributesInfo integerInfo = GetIntegerInfo();
434 0 : for (i = 0; i < integerInfo.mIntegerCount; i++) {
435 0 : if (aAttribute == *integerInfo.mIntegerInfo[i].mName) {
436 0 : rv = integerInfo.mIntegers[i].SetBaseValueString(aValue, this);
437 0 : if (NS_FAILED(rv)) {
438 0 : integerInfo.Reset(i);
439 : } else {
440 0 : aResult.SetTo(integerInfo.mIntegers[i].GetBaseValue(), &aValue);
441 0 : didSetResult = true;
442 : }
443 0 : foundMatch = true;
444 0 : break;
445 : }
446 : }
447 : }
448 :
449 0 : if (!foundMatch) {
450 : // Check for nsSVGIntegerPair attribute
451 0 : IntegerPairAttributesInfo integerPairInfo = GetIntegerPairInfo();
452 0 : for (i = 0; i < integerPairInfo.mIntegerPairCount; i++) {
453 0 : if (aAttribute == *integerPairInfo.mIntegerPairInfo[i].mName) {
454 : rv =
455 0 : integerPairInfo.mIntegerPairs[i].SetBaseValueString(aValue, this);
456 0 : if (NS_FAILED(rv)) {
457 0 : integerPairInfo.Reset(i);
458 : } else {
459 0 : aResult.SetTo(integerPairInfo.mIntegerPairs[i], &aValue);
460 0 : didSetResult = true;
461 : }
462 0 : foundMatch = true;
463 0 : break;
464 : }
465 : }
466 : }
467 :
468 0 : if (!foundMatch) {
469 : // Check for nsSVGAngle attribute
470 0 : AngleAttributesInfo angleInfo = GetAngleInfo();
471 0 : for (i = 0; i < angleInfo.mAngleCount; i++) {
472 0 : if (aAttribute == *angleInfo.mAngleInfo[i].mName) {
473 0 : rv = angleInfo.mAngles[i].SetBaseValueString(aValue, this, false);
474 0 : if (NS_FAILED(rv)) {
475 0 : angleInfo.Reset(i);
476 : } else {
477 0 : aResult.SetTo(angleInfo.mAngles[i], &aValue);
478 0 : didSetResult = true;
479 : }
480 0 : foundMatch = true;
481 0 : break;
482 : }
483 : }
484 : }
485 :
486 0 : if (!foundMatch) {
487 : // Check for nsSVGBoolean attribute
488 0 : BooleanAttributesInfo booleanInfo = GetBooleanInfo();
489 0 : for (i = 0; i < booleanInfo.mBooleanCount; i++) {
490 0 : if (aAttribute == *booleanInfo.mBooleanInfo[i].mName) {
491 0 : nsCOMPtr<nsIAtom> valAtom = do_GetAtom(aValue);
492 0 : rv = booleanInfo.mBooleans[i].SetBaseValueAtom(valAtom, this);
493 0 : if (NS_FAILED(rv)) {
494 0 : booleanInfo.Reset(i);
495 : } else {
496 0 : aResult.SetTo(valAtom);
497 0 : didSetResult = true;
498 : }
499 0 : foundMatch = true;
500 : break;
501 : }
502 : }
503 : }
504 :
505 0 : if (!foundMatch) {
506 : // Check for nsSVGEnum attribute
507 0 : EnumAttributesInfo enumInfo = GetEnumInfo();
508 0 : for (i = 0; i < enumInfo.mEnumCount; i++) {
509 0 : if (aAttribute == *enumInfo.mEnumInfo[i].mName) {
510 0 : nsCOMPtr<nsIAtom> valAtom = do_GetAtom(aValue);
511 0 : rv = enumInfo.mEnums[i].SetBaseValueAtom(valAtom, this);
512 0 : if (NS_FAILED(rv)) {
513 0 : enumInfo.Reset(i);
514 : } else {
515 0 : aResult.SetTo(valAtom);
516 0 : didSetResult = true;
517 : }
518 0 : foundMatch = true;
519 : break;
520 : }
521 : }
522 : }
523 :
524 0 : if (!foundMatch) {
525 : // Check for conditional processing attributes
526 0 : nsCOMPtr<DOMSVGTests> tests(do_QueryInterface(this));
527 0 : if (tests && tests->ParseConditionalProcessingAttribute(
528 0 : aAttribute, aValue, aResult)) {
529 0 : foundMatch = true;
530 : }
531 : }
532 :
533 0 : if (!foundMatch) {
534 : // Check for StringList attribute
535 0 : StringListAttributesInfo stringListInfo = GetStringListInfo();
536 0 : for (i = 0; i < stringListInfo.mStringListCount; i++) {
537 0 : if (aAttribute == *stringListInfo.mStringListInfo[i].mName) {
538 0 : rv = stringListInfo.mStringLists[i].SetValue(aValue);
539 0 : if (NS_FAILED(rv)) {
540 0 : stringListInfo.Reset(i);
541 : } else {
542 0 : aResult.SetTo(stringListInfo.mStringLists[i], &aValue);
543 0 : didSetResult = true;
544 : }
545 0 : foundMatch = true;
546 0 : break;
547 : }
548 : }
549 : }
550 :
551 0 : if (!foundMatch) {
552 : // Check for nsSVGViewBox attribute
553 0 : if (aAttribute == nsGkAtoms::viewBox) {
554 0 : nsSVGViewBox* viewBox = GetViewBox();
555 0 : if (viewBox) {
556 0 : rv = viewBox->SetBaseValueString(aValue, this);
557 0 : if (NS_FAILED(rv)) {
558 0 : viewBox->Init();
559 : } else {
560 0 : aResult.SetTo(*viewBox, &aValue);
561 0 : didSetResult = true;
562 : }
563 0 : foundMatch = true;
564 : }
565 : // Check for SVGAnimatedPreserveAspectRatio attribute
566 0 : } else if (aAttribute == nsGkAtoms::preserveAspectRatio) {
567 : SVGAnimatedPreserveAspectRatio *preserveAspectRatio =
568 0 : GetPreserveAspectRatio();
569 0 : if (preserveAspectRatio) {
570 0 : rv = preserveAspectRatio->SetBaseValueString(aValue, this);
571 0 : if (NS_FAILED(rv)) {
572 0 : preserveAspectRatio->Init();
573 : } else {
574 0 : aResult.SetTo(*preserveAspectRatio, &aValue);
575 0 : didSetResult = true;
576 : }
577 0 : foundMatch = true;
578 : }
579 : // Check for SVGAnimatedTransformList attribute
580 0 : } else if (GetTransformListAttrName() == aAttribute) {
581 0 : SVGAnimatedTransformList *transformList = GetAnimatedTransformList();
582 0 : if (transformList) {
583 0 : rv = transformList->SetBaseValueString(aValue);
584 0 : if (NS_FAILED(rv)) {
585 0 : transformList->ClearBaseValue();
586 : } else {
587 0 : aResult.SetTo(transformList->GetBaseValue(), &aValue);
588 0 : didSetResult = true;
589 : }
590 0 : foundMatch = true;
591 : }
592 : }
593 : }
594 : }
595 :
596 0 : if (!foundMatch) {
597 : // Check for nsSVGString attribute
598 0 : StringAttributesInfo stringInfo = GetStringInfo();
599 0 : for (PRUint32 i = 0; i < stringInfo.mStringCount; i++) {
600 0 : if (aNamespaceID == stringInfo.mStringInfo[i].mNamespaceID &&
601 0 : aAttribute == *stringInfo.mStringInfo[i].mName) {
602 0 : stringInfo.mStrings[i].SetBaseValue(aValue, this, false);
603 0 : foundMatch = true;
604 0 : break;
605 : }
606 : }
607 : }
608 :
609 0 : if (foundMatch) {
610 0 : if (NS_FAILED(rv)) {
611 0 : ReportAttributeParseFailure(OwnerDoc(), aAttribute, aValue);
612 0 : return false;
613 : }
614 0 : if (!didSetResult) {
615 0 : aResult.SetTo(aValue);
616 : }
617 0 : return true;
618 : }
619 :
620 : return nsSVGElementBase::ParseAttribute(aNamespaceID, aAttribute, aValue,
621 0 : aResult);
622 : }
623 :
624 : void
625 0 : nsSVGElement::UnsetAttrInternal(PRInt32 aNamespaceID, nsIAtom* aName,
626 : bool aNotify)
627 : {
628 : // XXXbz there's a bunch of redundancy here with AfterSetAttr.
629 : // Maybe consolidate?
630 :
631 0 : if (aNamespaceID == kNameSpaceID_None) {
632 : // If this is an svg presentation attribute, remove rule to force an update
633 0 : if (IsAttributeMapped(aName))
634 0 : mContentStyleRule = nsnull;
635 :
636 0 : if (IsEventName(aName)) {
637 0 : nsEventListenerManager* manager = GetListenerManager(false);
638 0 : if (manager) {
639 0 : nsIAtom* eventName = GetEventNameForAttr(aName);
640 0 : manager->RemoveScriptEventListener(eventName);
641 : }
642 0 : return;
643 : }
644 :
645 : // Check if this is a length attribute going away
646 0 : LengthAttributesInfo lenInfo = GetLengthInfo();
647 :
648 0 : for (PRUint32 i = 0; i < lenInfo.mLengthCount; i++) {
649 0 : if (aName == *lenInfo.mLengthInfo[i].mName) {
650 0 : MaybeSerializeAttrBeforeRemoval(aName, aNotify);
651 0 : lenInfo.Reset(i);
652 0 : return;
653 : }
654 : }
655 :
656 : // Check if this is a length list attribute going away
657 0 : LengthListAttributesInfo lengthListInfo = GetLengthListInfo();
658 :
659 0 : for (PRUint32 i = 0; i < lengthListInfo.mLengthListCount; i++) {
660 0 : if (aName == *lengthListInfo.mLengthListInfo[i].mName) {
661 0 : MaybeSerializeAttrBeforeRemoval(aName, aNotify);
662 0 : lengthListInfo.Reset(i);
663 0 : return;
664 : }
665 : }
666 :
667 : // Check if this is a number list attribute going away
668 0 : NumberListAttributesInfo numberListInfo = GetNumberListInfo();
669 :
670 0 : for (PRUint32 i = 0; i < numberListInfo.mNumberListCount; i++) {
671 0 : if (aName == *numberListInfo.mNumberListInfo[i].mName) {
672 0 : MaybeSerializeAttrBeforeRemoval(aName, aNotify);
673 0 : numberListInfo.Reset(i);
674 0 : return;
675 : }
676 : }
677 :
678 : // Check if this is a point list attribute going away
679 0 : if (GetPointListAttrName() == aName) {
680 0 : SVGAnimatedPointList *pointList = GetAnimatedPointList();
681 0 : if (pointList) {
682 0 : MaybeSerializeAttrBeforeRemoval(aName, aNotify);
683 0 : pointList->ClearBaseValue();
684 0 : return;
685 : }
686 : }
687 :
688 : // Check if this is a path segment list attribute going away
689 0 : if (GetPathDataAttrName() == aName) {
690 0 : SVGAnimatedPathSegList *segList = GetAnimPathSegList();
691 0 : if (segList) {
692 0 : MaybeSerializeAttrBeforeRemoval(aName, aNotify);
693 0 : segList->ClearBaseValue();
694 0 : return;
695 : }
696 : }
697 :
698 : // Check if this is a number attribute going away
699 0 : NumberAttributesInfo numInfo = GetNumberInfo();
700 :
701 0 : for (PRUint32 i = 0; i < numInfo.mNumberCount; i++) {
702 0 : if (aName == *numInfo.mNumberInfo[i].mName) {
703 0 : numInfo.Reset(i);
704 0 : return;
705 : }
706 : }
707 :
708 : // Check if this is a number pair attribute going away
709 0 : NumberPairAttributesInfo numPairInfo = GetNumberPairInfo();
710 :
711 0 : for (PRUint32 i = 0; i < numPairInfo.mNumberPairCount; i++) {
712 0 : if (aName == *numPairInfo.mNumberPairInfo[i].mName) {
713 0 : MaybeSerializeAttrBeforeRemoval(aName, aNotify);
714 0 : numPairInfo.Reset(i);
715 0 : return;
716 : }
717 : }
718 :
719 : // Check if this is an integer attribute going away
720 0 : IntegerAttributesInfo intInfo = GetIntegerInfo();
721 :
722 0 : for (PRUint32 i = 0; i < intInfo.mIntegerCount; i++) {
723 0 : if (aName == *intInfo.mIntegerInfo[i].mName) {
724 0 : intInfo.Reset(i);
725 0 : return;
726 : }
727 : }
728 :
729 : // Check if this is an integer pair attribute going away
730 0 : IntegerPairAttributesInfo intPairInfo = GetIntegerPairInfo();
731 :
732 0 : for (PRUint32 i = 0; i < intPairInfo.mIntegerPairCount; i++) {
733 0 : if (aName == *intPairInfo.mIntegerPairInfo[i].mName) {
734 0 : MaybeSerializeAttrBeforeRemoval(aName, aNotify);
735 0 : intPairInfo.Reset(i);
736 0 : return;
737 : }
738 : }
739 :
740 : // Check if this is an angle attribute going away
741 0 : AngleAttributesInfo angleInfo = GetAngleInfo();
742 :
743 0 : for (PRUint32 i = 0; i < angleInfo.mAngleCount; i++) {
744 0 : if (aName == *angleInfo.mAngleInfo[i].mName) {
745 0 : MaybeSerializeAttrBeforeRemoval(aName, aNotify);
746 0 : angleInfo.Reset(i);
747 0 : return;
748 : }
749 : }
750 :
751 : // Check if this is a boolean attribute going away
752 0 : BooleanAttributesInfo boolInfo = GetBooleanInfo();
753 :
754 0 : for (PRUint32 i = 0; i < boolInfo.mBooleanCount; i++) {
755 0 : if (aName == *boolInfo.mBooleanInfo[i].mName) {
756 0 : boolInfo.Reset(i);
757 0 : return;
758 : }
759 : }
760 :
761 : // Check if this is an enum attribute going away
762 0 : EnumAttributesInfo enumInfo = GetEnumInfo();
763 :
764 0 : for (PRUint32 i = 0; i < enumInfo.mEnumCount; i++) {
765 0 : if (aName == *enumInfo.mEnumInfo[i].mName) {
766 0 : enumInfo.Reset(i);
767 0 : return;
768 : }
769 : }
770 :
771 : // Check if this is a nsViewBox attribute going away
772 0 : if (aName == nsGkAtoms::viewBox) {
773 0 : nsSVGViewBox* viewBox = GetViewBox();
774 0 : if (viewBox) {
775 0 : MaybeSerializeAttrBeforeRemoval(aName, aNotify);
776 0 : viewBox->Init();
777 0 : return;
778 : }
779 : }
780 :
781 : // Check if this is a preserveAspectRatio attribute going away
782 0 : if (aName == nsGkAtoms::preserveAspectRatio) {
783 : SVGAnimatedPreserveAspectRatio *preserveAspectRatio =
784 0 : GetPreserveAspectRatio();
785 0 : if (preserveAspectRatio) {
786 0 : MaybeSerializeAttrBeforeRemoval(aName, aNotify);
787 0 : preserveAspectRatio->Init();
788 0 : return;
789 : }
790 : }
791 :
792 : // Check if this is a transform list attribute going away
793 0 : if (GetTransformListAttrName() == aName) {
794 0 : SVGAnimatedTransformList *transformList = GetAnimatedTransformList();
795 0 : if (transformList) {
796 0 : MaybeSerializeAttrBeforeRemoval(aName, aNotify);
797 0 : transformList->ClearBaseValue();
798 0 : return;
799 : }
800 : }
801 :
802 : // Check for conditional processing attributes
803 0 : nsCOMPtr<DOMSVGTests> tests(do_QueryInterface(this));
804 0 : if (tests && tests->IsConditionalProcessingAttribute(aName)) {
805 0 : MaybeSerializeAttrBeforeRemoval(aName, aNotify);
806 0 : tests->UnsetAttr(aName);
807 : return;
808 : }
809 :
810 : // Check if this is a string list attribute going away
811 0 : StringListAttributesInfo stringListInfo = GetStringListInfo();
812 :
813 0 : for (PRUint32 i = 0; i < stringListInfo.mStringListCount; i++) {
814 0 : if (aName == *stringListInfo.mStringListInfo[i].mName) {
815 0 : MaybeSerializeAttrBeforeRemoval(aName, aNotify);
816 0 : stringListInfo.Reset(i);
817 : return;
818 : }
819 : }
820 : }
821 :
822 : // Check if this is a string attribute going away
823 0 : StringAttributesInfo stringInfo = GetStringInfo();
824 :
825 0 : for (PRUint32 i = 0; i < stringInfo.mStringCount; i++) {
826 0 : if (aNamespaceID == stringInfo.mStringInfo[i].mNamespaceID &&
827 0 : aName == *stringInfo.mStringInfo[i].mName) {
828 0 : stringInfo.Reset(i);
829 0 : return;
830 : }
831 : }
832 : }
833 :
834 : nsresult
835 0 : nsSVGElement::UnsetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
836 : bool aNotify)
837 : {
838 0 : UnsetAttrInternal(aNamespaceID, aName, aNotify);
839 0 : return nsSVGElementBase::UnsetAttr(aNamespaceID, aName, aNotify);
840 : }
841 :
842 : nsChangeHint
843 0 : nsSVGElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
844 : PRInt32 aModType) const
845 : {
846 : nsChangeHint retval =
847 0 : nsSVGElementBase::GetAttributeChangeHint(aAttribute, aModType);
848 :
849 0 : nsCOMPtr<DOMSVGTests> tests(do_QueryInterface(const_cast<nsSVGElement*>(this)));
850 0 : if (tests && tests->IsConditionalProcessingAttribute(aAttribute)) {
851 : // It would be nice to only reconstruct the frame if the value returned by
852 : // DOMSVGTests::PassesConditionalProcessingTests has changed, but we don't
853 : // know that
854 0 : NS_UpdateHint(retval, nsChangeHint_ReconstructFrame);
855 : }
856 0 : return retval;
857 : }
858 :
859 : bool
860 0 : nsSVGElement::IsNodeOfType(PRUint32 aFlags) const
861 : {
862 0 : return !(aFlags & ~eCONTENT);
863 : }
864 :
865 : NS_IMETHODIMP
866 0 : nsSVGElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
867 : {
868 : #ifdef DEBUG
869 : // printf("nsSVGElement(%p)::WalkContentStyleRules()\n", this);
870 : #endif
871 0 : if (!mContentStyleRule)
872 0 : UpdateContentStyleRule();
873 :
874 0 : if (mContentStyleRule) {
875 0 : mContentStyleRule->RuleMatched();
876 0 : aRuleWalker->Forward(mContentStyleRule);
877 : }
878 :
879 : // Update & walk the animated content style rule, to include style from
880 : // animated mapped attributes. But first, get nsPresContext to check
881 : // whether this is a "no-animation restyle". (This should match the check
882 : // in nsHTMLCSSStyleSheet::RulesMatching(), where we determine whether to
883 : // apply the SMILOverrideStyle.)
884 0 : nsIDocument* doc = OwnerDoc();
885 0 : nsIPresShell* shell = doc->GetShell();
886 0 : nsPresContext* context = shell ? shell->GetPresContext() : nsnull;
887 0 : if (context && context->IsProcessingRestyles() &&
888 0 : !context->IsProcessingAnimationStyleChange()) {
889 : // Any style changes right now could trigger CSS Transitions. We don't
890 : // want that to happen from SMIL-animated value of mapped attrs, so
891 : // ignore animated value for now, and request an animation restyle to
892 : // get our animated value noticed.
893 0 : shell->RestyleForAnimation(this, eRestyle_Self);
894 : } else {
895 : // Ok, this is an animation restyle -- go ahead and update/walk the
896 : // animated content style rule.
897 0 : css::StyleRule* animContentStyleRule = GetAnimatedContentStyleRule();
898 0 : if (!animContentStyleRule) {
899 0 : UpdateAnimatedContentStyleRule();
900 0 : animContentStyleRule = GetAnimatedContentStyleRule();
901 : }
902 0 : if (animContentStyleRule) {
903 0 : animContentStyleRule->RuleMatched();
904 0 : aRuleWalker->Forward(animContentStyleRule);
905 : }
906 : }
907 :
908 0 : return NS_OK;
909 : }
910 :
911 : NS_IMETHODIMP_(bool)
912 0 : nsSVGElement::IsAttributeMapped(const nsIAtom* name) const
913 : {
914 0 : if (name == nsGkAtoms::lang) {
915 0 : return true;
916 : }
917 0 : return nsSVGElementBase::IsAttributeMapped(name);
918 : }
919 :
920 : // PresentationAttributes-FillStroke
921 : /* static */ const nsGenericElement::MappedAttributeEntry
922 : nsSVGElement::sFillStrokeMap[] = {
923 : { &nsGkAtoms::fill },
924 : { &nsGkAtoms::fill_opacity },
925 : { &nsGkAtoms::fill_rule },
926 : { &nsGkAtoms::stroke },
927 : { &nsGkAtoms::stroke_dasharray },
928 : { &nsGkAtoms::stroke_dashoffset },
929 : { &nsGkAtoms::stroke_linecap },
930 : { &nsGkAtoms::stroke_linejoin },
931 : { &nsGkAtoms::stroke_miterlimit },
932 : { &nsGkAtoms::stroke_opacity },
933 : { &nsGkAtoms::stroke_width },
934 : { nsnull }
935 : };
936 :
937 : // PresentationAttributes-Graphics
938 : /* static */ const nsGenericElement::MappedAttributeEntry
939 : nsSVGElement::sGraphicsMap[] = {
940 : { &nsGkAtoms::clip_path },
941 : { &nsGkAtoms::clip_rule },
942 : { &nsGkAtoms::colorInterpolation },
943 : { &nsGkAtoms::cursor },
944 : { &nsGkAtoms::display },
945 : { &nsGkAtoms::filter },
946 : { &nsGkAtoms::image_rendering },
947 : { &nsGkAtoms::mask },
948 : { &nsGkAtoms::opacity },
949 : { &nsGkAtoms::pointer_events },
950 : { &nsGkAtoms::shape_rendering },
951 : { &nsGkAtoms::text_rendering },
952 : { &nsGkAtoms::visibility },
953 : { nsnull }
954 : };
955 :
956 : // PresentationAttributes-TextContentElements
957 : /* static */ const nsGenericElement::MappedAttributeEntry
958 : nsSVGElement::sTextContentElementsMap[] = {
959 : { &nsGkAtoms::alignment_baseline },
960 : { &nsGkAtoms::baseline_shift },
961 : { &nsGkAtoms::direction },
962 : { &nsGkAtoms::dominant_baseline },
963 : { &nsGkAtoms::glyph_orientation_horizontal },
964 : { &nsGkAtoms::glyph_orientation_vertical },
965 : { &nsGkAtoms::kerning },
966 : { &nsGkAtoms::letter_spacing },
967 : { &nsGkAtoms::text_anchor },
968 : { &nsGkAtoms::text_decoration },
969 : { &nsGkAtoms::unicode_bidi },
970 : { &nsGkAtoms::word_spacing },
971 : { nsnull }
972 : };
973 :
974 : // PresentationAttributes-FontSpecification
975 : /* static */ const nsGenericElement::MappedAttributeEntry
976 : nsSVGElement::sFontSpecificationMap[] = {
977 : { &nsGkAtoms::font_family },
978 : { &nsGkAtoms::font_size },
979 : { &nsGkAtoms::font_size_adjust },
980 : { &nsGkAtoms::font_stretch },
981 : { &nsGkAtoms::font_style },
982 : { &nsGkAtoms::font_variant },
983 : { &nsGkAtoms::fontWeight },
984 : { nsnull }
985 : };
986 :
987 : // PresentationAttributes-GradientStop
988 : /* static */ const nsGenericElement::MappedAttributeEntry
989 : nsSVGElement::sGradientStopMap[] = {
990 : { &nsGkAtoms::stop_color },
991 : { &nsGkAtoms::stop_opacity },
992 : { nsnull }
993 : };
994 :
995 : // PresentationAttributes-Viewports
996 : /* static */ const nsGenericElement::MappedAttributeEntry
997 : nsSVGElement::sViewportsMap[] = {
998 : { &nsGkAtoms::overflow },
999 : { &nsGkAtoms::clip },
1000 : { nsnull }
1001 : };
1002 :
1003 : // PresentationAttributes-Makers
1004 : /* static */ const nsGenericElement::MappedAttributeEntry
1005 : nsSVGElement::sMarkersMap[] = {
1006 : { &nsGkAtoms::marker_end },
1007 : { &nsGkAtoms::marker_mid },
1008 : { &nsGkAtoms::marker_start },
1009 : { nsnull }
1010 : };
1011 :
1012 : // PresentationAttributes-Color
1013 : /* static */ const nsGenericElement::MappedAttributeEntry
1014 : nsSVGElement::sColorMap[] = {
1015 : { &nsGkAtoms::color },
1016 : { nsnull }
1017 : };
1018 :
1019 : // PresentationAttributes-Filters
1020 : /* static */ const nsGenericElement::MappedAttributeEntry
1021 : nsSVGElement::sFiltersMap[] = {
1022 : { &nsGkAtoms::colorInterpolationFilters },
1023 : { nsnull }
1024 : };
1025 :
1026 : // PresentationAttributes-feFlood
1027 : /* static */ const nsGenericElement::MappedAttributeEntry
1028 : nsSVGElement::sFEFloodMap[] = {
1029 : { &nsGkAtoms::flood_color },
1030 : { &nsGkAtoms::flood_opacity },
1031 : { nsnull }
1032 : };
1033 :
1034 : // PresentationAttributes-LightingEffects
1035 : /* static */ const nsGenericElement::MappedAttributeEntry
1036 : nsSVGElement::sLightingEffectsMap[] = {
1037 : { &nsGkAtoms::lighting_color },
1038 : { nsnull }
1039 : };
1040 :
1041 : //----------------------------------------------------------------------
1042 : // nsIDOMNode methods
1043 :
1044 : NS_IMETHODIMP
1045 0 : nsSVGElement::IsSupported(const nsAString& aFeature, const nsAString& aVersion, bool* aReturn)
1046 : {
1047 0 : return nsGenericElement::IsSupported(aFeature, aVersion, aReturn);
1048 : }
1049 :
1050 : //----------------------------------------------------------------------
1051 : // nsIDOMElement methods
1052 :
1053 : // forwarded to nsGenericElement implementations
1054 :
1055 :
1056 : //----------------------------------------------------------------------
1057 : // nsIDOMSVGElement methods
1058 :
1059 : /* attribute DOMString id; */
1060 0 : NS_IMETHODIMP nsSVGElement::GetId(nsAString & aId)
1061 : {
1062 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::id, aId);
1063 :
1064 0 : return NS_OK;
1065 : }
1066 :
1067 0 : NS_IMETHODIMP nsSVGElement::SetId(const nsAString & aId)
1068 : {
1069 0 : return SetAttr(kNameSpaceID_None, nsGkAtoms::id, aId, true);
1070 : }
1071 :
1072 : /* readonly attribute nsIDOMSVGSVGElement ownerSVGElement; */
1073 : NS_IMETHODIMP
1074 0 : nsSVGElement::GetOwnerSVGElement(nsIDOMSVGSVGElement * *aOwnerSVGElement)
1075 : {
1076 0 : NS_IF_ADDREF(*aOwnerSVGElement = GetCtx());
1077 :
1078 0 : if (*aOwnerSVGElement || Tag() == nsGkAtoms::svg) {
1079 : // If we found something or we're the outermost SVG element, that's OK.
1080 0 : return NS_OK;
1081 : }
1082 : // Otherwise, we've got an invalid structure
1083 0 : return NS_ERROR_FAILURE;
1084 : }
1085 :
1086 : /* readonly attribute nsIDOMSVGElement viewportElement; */
1087 : NS_IMETHODIMP
1088 0 : nsSVGElement::GetViewportElement(nsIDOMSVGElement * *aViewportElement)
1089 : {
1090 0 : *aViewportElement = nsSVGUtils::GetNearestViewportElement(this).get();
1091 0 : return NS_OK;
1092 : }
1093 :
1094 : //------------------------------------------------------------------------
1095 : // Helper class: MappedAttrParser, for parsing values of mapped attributes
1096 :
1097 : namespace {
1098 :
1099 : class MappedAttrParser {
1100 : public:
1101 : MappedAttrParser(css::Loader* aLoader,
1102 : nsIURI* aDocURI,
1103 : already_AddRefed<nsIURI> aBaseURI,
1104 : nsIPrincipal* aNodePrincipal);
1105 : ~MappedAttrParser();
1106 :
1107 : // Parses a mapped attribute value.
1108 : void ParseMappedAttrValue(nsIAtom* aMappedAttrName,
1109 : nsAString& aMappedAttrValue);
1110 :
1111 : // If we've parsed any values for mapped attributes, this method returns
1112 : // a new already_AddRefed css::StyleRule that incorporates the parsed
1113 : // values. Otherwise, this method returns null.
1114 : already_AddRefed<css::StyleRule> CreateStyleRule();
1115 :
1116 : private:
1117 : // MEMBER DATA
1118 : // -----------
1119 : nsCSSParser mParser;
1120 :
1121 : // Arguments for nsCSSParser::ParseProperty
1122 : nsIURI* mDocURI;
1123 : nsCOMPtr<nsIURI> mBaseURI;
1124 : nsIPrincipal* mNodePrincipal;
1125 :
1126 : // Declaration for storing parsed values (lazily initialized)
1127 : css::Declaration* mDecl;
1128 : };
1129 :
1130 0 : MappedAttrParser::MappedAttrParser(css::Loader* aLoader,
1131 : nsIURI* aDocURI,
1132 : already_AddRefed<nsIURI> aBaseURI,
1133 : nsIPrincipal* aNodePrincipal)
1134 : : mParser(aLoader), mDocURI(aDocURI), mBaseURI(aBaseURI),
1135 0 : mNodePrincipal(aNodePrincipal), mDecl(nsnull)
1136 : {
1137 : // SVG and CSS differ slightly in their interpretation of some of
1138 : // the attributes. SVG allows attributes of the form: font-size="5"
1139 : // (style="font-size: 5" if using a style attribute)
1140 : // where CSS requires units: font-size="5pt" (style="font-size: 5pt")
1141 : // Set a flag to pass information to the parser so that we can use
1142 : // the CSS parser to parse the font-size attribute. Note that this
1143 : // does *not* affect the use of CSS stylesheets, which will still
1144 : // require units.
1145 0 : mParser.SetSVGMode(true);
1146 0 : }
1147 :
1148 0 : MappedAttrParser::~MappedAttrParser()
1149 : {
1150 0 : NS_ABORT_IF_FALSE(!mDecl,
1151 : "If mDecl was initialized, it should have been converted "
1152 : "into a style rule (and had its pointer cleared)");
1153 0 : }
1154 :
1155 : void
1156 0 : MappedAttrParser::ParseMappedAttrValue(nsIAtom* aMappedAttrName,
1157 : nsAString& aMappedAttrValue)
1158 : {
1159 0 : if (!mDecl) {
1160 0 : mDecl = new css::Declaration();
1161 0 : mDecl->InitializeEmpty();
1162 : }
1163 :
1164 : // Get the nsCSSProperty ID for our mapped attribute.
1165 : nsCSSProperty propertyID =
1166 0 : nsCSSProps::LookupProperty(nsDependentAtomString(aMappedAttrName));
1167 0 : if (propertyID != eCSSProperty_UNKNOWN) {
1168 : bool changed; // outparam for ParseProperty. (ignored)
1169 : mParser.ParseProperty(propertyID, aMappedAttrValue, mDocURI, mBaseURI,
1170 0 : mNodePrincipal, mDecl, &changed, false);
1171 0 : return;
1172 : }
1173 0 : NS_ABORT_IF_FALSE(aMappedAttrName == nsGkAtoms::lang,
1174 : "Only 'lang' should be unrecognized!");
1175 : // nsCSSParser doesn't know about 'lang', so we need to handle it specially.
1176 0 : if (aMappedAttrName == nsGkAtoms::lang) {
1177 0 : propertyID = eCSSProperty__x_lang;
1178 0 : nsCSSExpandedDataBlock block;
1179 0 : mDecl->ExpandTo(&block);
1180 0 : nsCSSValue cssValue(PromiseFlatString(aMappedAttrValue), eCSSUnit_Ident);
1181 0 : block.AddLonghandProperty(propertyID, cssValue);
1182 0 : mDecl->ValueAppended(propertyID);
1183 0 : mDecl->CompressFrom(&block);
1184 : }
1185 : }
1186 :
1187 : already_AddRefed<css::StyleRule>
1188 0 : MappedAttrParser::CreateStyleRule()
1189 : {
1190 0 : if (!mDecl) {
1191 0 : return nsnull; // No mapped attributes were parsed
1192 : }
1193 :
1194 0 : nsRefPtr<css::StyleRule> rule = new css::StyleRule(nsnull, mDecl);
1195 0 : mDecl = nsnull; // We no longer own the declaration -- drop our pointer to it
1196 0 : return rule.forget();
1197 : }
1198 :
1199 : } // anonymous namespace
1200 :
1201 : //----------------------------------------------------------------------
1202 : // Implementation Helpers:
1203 :
1204 : bool
1205 0 : nsSVGElement::IsEventName(nsIAtom* aName)
1206 : {
1207 0 : return false;
1208 : }
1209 :
1210 : void
1211 0 : nsSVGElement::UpdateContentStyleRule()
1212 : {
1213 0 : NS_ASSERTION(!mContentStyleRule, "we already have a content style rule");
1214 :
1215 0 : PRUint32 attrCount = mAttrsAndChildren.AttrCount();
1216 0 : if (!attrCount) {
1217 : // nothing to do
1218 0 : return;
1219 : }
1220 :
1221 0 : nsIDocument* doc = OwnerDoc();
1222 : MappedAttrParser mappedAttrParser(doc->CSSLoader(), doc->GetDocumentURI(),
1223 0 : GetBaseURI(), NodePrincipal());
1224 :
1225 0 : for (PRUint32 i = 0; i < attrCount; ++i) {
1226 0 : const nsAttrName* attrName = mAttrsAndChildren.AttrNameAt(i);
1227 0 : if (!attrName->IsAtom() || !IsAttributeMapped(attrName->Atom()))
1228 0 : continue;
1229 :
1230 0 : if (attrName->NamespaceID() != kNameSpaceID_None &&
1231 0 : !attrName->Equals(nsGkAtoms::lang, kNameSpaceID_XML)) {
1232 0 : continue;
1233 : }
1234 :
1235 0 : if (attrName->Equals(nsGkAtoms::lang, kNameSpaceID_None) &&
1236 0 : HasAttr(kNameSpaceID_XML, nsGkAtoms::lang)) {
1237 0 : continue; // xml:lang has precedence
1238 : }
1239 :
1240 0 : if (Tag() == nsGkAtoms::svg) {
1241 : // Special case: we don't want <svg> 'width'/'height' mapped into style
1242 : // if the attribute value isn't a valid <length> according to SVG (which
1243 : // only supports a subset of the CSS <length> values). We don't enforce
1244 : // this by checking the attribute value in nsSVGSVGElement::
1245 : // IsAttributeMapped since we don't want that method to depend on the
1246 : // value of the attribute that is being checked. Rather we just prevent
1247 : // the actual mapping here, as necessary.
1248 0 : if (attrName->Atom() == nsGkAtoms::width &&
1249 0 : !GetAnimatedLength(nsGkAtoms::width)->HasBaseVal()) {
1250 0 : continue;
1251 : }
1252 0 : if (attrName->Atom() == nsGkAtoms::height &&
1253 0 : !GetAnimatedLength(nsGkAtoms::height)->HasBaseVal()) {
1254 0 : continue;
1255 : }
1256 : }
1257 :
1258 0 : nsAutoString value;
1259 0 : mAttrsAndChildren.AttrAt(i)->ToString(value);
1260 0 : mappedAttrParser.ParseMappedAttrValue(attrName->Atom(), value);
1261 : }
1262 0 : mContentStyleRule = mappedAttrParser.CreateStyleRule();
1263 : }
1264 :
1265 : static void
1266 0 : ParseMappedAttrAnimValueCallback(void* aObject,
1267 : nsIAtom* aPropertyName,
1268 : void* aPropertyValue,
1269 : void* aData)
1270 : {
1271 0 : NS_ABORT_IF_FALSE(aPropertyName != SMIL_MAPPED_ATTR_STYLERULE_ATOM,
1272 : "animated content style rule should have been removed "
1273 : "from properties table already (we're rebuilding it now)");
1274 :
1275 : MappedAttrParser* mappedAttrParser =
1276 0 : static_cast<MappedAttrParser*>(aData);
1277 :
1278 0 : nsStringBuffer* valueBuf = static_cast<nsStringBuffer*>(aPropertyValue);
1279 0 : nsAutoString value;
1280 0 : PRUint32 len = NS_strlen(static_cast<PRUnichar*>(valueBuf->Data()));
1281 0 : valueBuf->ToString(len, value);
1282 :
1283 0 : mappedAttrParser->ParseMappedAttrValue(aPropertyName, value);
1284 0 : }
1285 :
1286 : // Callback for freeing animated content style rule, in property table.
1287 : static void
1288 0 : ReleaseStyleRule(void* aObject, /* unused */
1289 : nsIAtom* aPropertyName,
1290 : void* aPropertyValue,
1291 : void* aData /* unused */)
1292 : {
1293 0 : NS_ABORT_IF_FALSE(aPropertyName == SMIL_MAPPED_ATTR_STYLERULE_ATOM,
1294 : "unexpected property name, for "
1295 : "animated content style rule");
1296 0 : css::StyleRule* styleRule = static_cast<css::StyleRule*>(aPropertyValue);
1297 0 : NS_ABORT_IF_FALSE(styleRule, "unexpected null style rule");
1298 0 : styleRule->Release();
1299 0 : }
1300 :
1301 : void
1302 0 : nsSVGElement::UpdateAnimatedContentStyleRule()
1303 : {
1304 0 : NS_ABORT_IF_FALSE(!GetAnimatedContentStyleRule(),
1305 : "Animated content style rule already set");
1306 :
1307 0 : nsIDocument* doc = OwnerDoc();
1308 0 : if (!doc) {
1309 0 : NS_ERROR("SVG element without owner document");
1310 0 : return;
1311 : }
1312 :
1313 : MappedAttrParser mappedAttrParser(doc->CSSLoader(), doc->GetDocumentURI(),
1314 0 : GetBaseURI(), NodePrincipal());
1315 : doc->PropertyTable(SMIL_MAPPED_ATTR_ANIMVAL)->
1316 0 : Enumerate(this, ParseMappedAttrAnimValueCallback, &mappedAttrParser);
1317 :
1318 : nsRefPtr<css::StyleRule>
1319 0 : animContentStyleRule(mappedAttrParser.CreateStyleRule());
1320 :
1321 0 : if (animContentStyleRule) {
1322 : #ifdef DEBUG
1323 : nsresult rv =
1324 : #endif
1325 : SetProperty(SMIL_MAPPED_ATTR_ANIMVAL,
1326 : SMIL_MAPPED_ATTR_STYLERULE_ATOM,
1327 0 : animContentStyleRule.get(),
1328 0 : ReleaseStyleRule);
1329 0 : animContentStyleRule.forget();
1330 0 : NS_ABORT_IF_FALSE(rv == NS_OK,
1331 : "SetProperty failed (or overwrote something)");
1332 : }
1333 : }
1334 :
1335 : css::StyleRule*
1336 0 : nsSVGElement::GetAnimatedContentStyleRule()
1337 : {
1338 : return
1339 : static_cast<css::StyleRule*>(GetProperty(SMIL_MAPPED_ATTR_ANIMVAL,
1340 : SMIL_MAPPED_ATTR_STYLERULE_ATOM,
1341 0 : nsnull));
1342 : }
1343 :
1344 : /**
1345 : * Helper methods for the type-specific WillChangeXXX methods.
1346 : *
1347 : * This method sends out appropriate pre-change notifications so that selector
1348 : * restyles (e.g. due to changes that cause |elem[attr="val"]| to start/stop
1349 : * matching) work, and it returns an nsAttrValue that _may_ contain the
1350 : * attribute's pre-change value.
1351 : *
1352 : * The nsAttrValue returned by this method depends on whether there are
1353 : * mutation event listeners listening for changes to this element's attributes.
1354 : * If not, then the object returned is empty. If there are, then the
1355 : * nsAttrValue returned contains a serialized copy of the attribute's value
1356 : * prior to the change, and this object should be passed to the corresponding
1357 : * DidChangeXXX method call (assuming a WillChangeXXX call is required for the
1358 : * SVG type - see comment below). This is necessary so that the 'prevValue'
1359 : * property of the mutation event that is dispatched will correctly contain the
1360 : * old value.
1361 : *
1362 : * The reason we need to serialize the old value if there are mutation
1363 : * event listeners is because the underlying nsAttrValue for the attribute
1364 : * points directly to a parsed representation of the attribute (e.g. an
1365 : * SVGAnimatedLengthList*) that is a member of the SVG element. That object
1366 : * will have changed by the time DidChangeXXX has been called, so without the
1367 : * serialization of the old attribute value that we provide, DidChangeXXX
1368 : * would have no way to get the old value to pass to SetAttrAndNotify.
1369 : *
1370 : * We only return the old value when there are mutation event listeners because
1371 : * it's not needed otherwise, and because it's expensive to serialize the old
1372 : * value. This is especially true for list type attributes, which may be built
1373 : * up via the SVG DOM resulting in a large number of Will/DidModifyXXX calls
1374 : * before the script finally finishes setting the attribute.
1375 : *
1376 : * Note that unlike using SetParsedAttr, using Will/DidChangeXXX does NOT check
1377 : * and filter out redundant changes. Before calling WillChangeXXX, the caller
1378 : * should check whether the new and old values are actually the same, and skip
1379 : * calling Will/DidChangeXXX if they are.
1380 : *
1381 : * Also note that not all SVG types use this scheme. For types that can be
1382 : * represented by an nsAttrValue without pointing back to an SVG object (e.g.
1383 : * enums, booleans, integers) we can simply use SetParsedAttr which will do all
1384 : * of the above for us. For such types there is no matching WillChangeXXX
1385 : * method, only DidChangeXXX which calls SetParsedAttr.
1386 : */
1387 : nsAttrValue
1388 0 : nsSVGElement::WillChangeValue(nsIAtom* aName)
1389 : {
1390 : // We need an empty attr value:
1391 : // a) to pass to BeforeSetAttr when GetParsedAttr returns nsnull
1392 : // b) to store the old value in the case we have mutation listeners
1393 : // We can use the same value for both purposes since (a) happens before (b).
1394 : // Also, we should be careful to always return this value to benefit from
1395 : // return value optimization.
1396 0 : nsAttrValue emptyOrOldAttrValue;
1397 0 : const nsAttrValue* attrValue = GetParsedAttr(aName);
1398 :
1399 : // This is not strictly correct--the attribute value parameter for
1400 : // BeforeSetAttr should reflect the value that *will* be set but that implies
1401 : // allocating, e.g. an extra nsSVGLength2, and isn't necessary at the moment
1402 : // since no SVG elements overload BeforeSetAttr. For now we just pass the
1403 : // current value.
1404 : nsAttrValueOrString attrStringOrValue(attrValue ? *attrValue
1405 0 : : emptyOrOldAttrValue);
1406 : DebugOnly<nsresult> rv =
1407 : BeforeSetAttr(kNameSpaceID_None, aName, &attrStringOrValue,
1408 0 : kNotifyDocumentObservers);
1409 : // SVG elements aren't expected to overload BeforeSetAttr in such a way that
1410 : // it may fail. So long as this is the case we don't need to check and pass on
1411 : // the return value which simplifies the calling code significantly.
1412 0 : NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "Unexpected failure from BeforeSetAttr");
1413 :
1414 : // We only need to set the old value if we have listeners since otherwise it
1415 : // isn't used.
1416 0 : if (attrValue &&
1417 : nsContentUtils::HasMutationListeners(this,
1418 : NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
1419 0 : this)) {
1420 0 : emptyOrOldAttrValue.SetToSerialized(*attrValue);
1421 : }
1422 :
1423 : PRUint8 modType = attrValue
1424 : ? static_cast<PRUint8>(nsIDOMMutationEvent::MODIFICATION)
1425 0 : : static_cast<PRUint8>(nsIDOMMutationEvent::ADDITION);
1426 0 : nsNodeUtils::AttributeWillChange(this, kNameSpaceID_None, aName, modType);
1427 :
1428 : return emptyOrOldAttrValue;
1429 : }
1430 :
1431 : /**
1432 : * Helper methods for the type-specific DidChangeXXX methods.
1433 : *
1434 : * aEmptyOrOldValue will normally be the object returned from the corresponding
1435 : * WillChangeXXX call. This is because:
1436 : * a) WillChangeXXX will ensure the object is set when we have mutation
1437 : * listeners, and
1438 : * b) WillChangeXXX will ensure the object represents a serialized version of
1439 : * the old attribute value so that the value doesn't change when the
1440 : * underlying SVG type is updated.
1441 : */
1442 : void
1443 0 : nsSVGElement::DidChangeValue(nsIAtom* aName,
1444 : const nsAttrValue& aEmptyOrOldValue,
1445 : nsAttrValue& aNewValue)
1446 : {
1447 : bool hasListeners =
1448 : nsContentUtils::HasMutationListeners(this,
1449 : NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
1450 0 : this);
1451 0 : PRUint8 modType = HasAttr(kNameSpaceID_None, aName)
1452 : ? static_cast<PRUint8>(nsIDOMMutationEvent::MODIFICATION)
1453 0 : : static_cast<PRUint8>(nsIDOMMutationEvent::ADDITION);
1454 : SetAttrAndNotify(kNameSpaceID_None, aName, nsnull, aEmptyOrOldValue,
1455 : aNewValue, modType, hasListeners, kNotifyDocumentObservers,
1456 0 : kCallAfterSetAttr);
1457 0 : }
1458 :
1459 : void
1460 0 : nsSVGElement::MaybeSerializeAttrBeforeRemoval(nsIAtom* aName, bool aNotify)
1461 : {
1462 0 : if (!aNotify ||
1463 : !nsContentUtils::HasMutationListeners(this,
1464 : NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
1465 0 : this)) {
1466 0 : return;
1467 : }
1468 :
1469 0 : const nsAttrValue* attrValue = mAttrsAndChildren.GetAttr(aName);
1470 0 : if (!attrValue)
1471 0 : return;
1472 :
1473 0 : nsAutoString serializedValue;
1474 0 : attrValue->ToString(serializedValue);
1475 0 : nsAttrValue oldAttrValue(serializedValue);
1476 0 : mAttrsAndChildren.SetAndTakeAttr(aName, oldAttrValue);
1477 : }
1478 :
1479 : /* static */
1480 0 : nsIAtom* nsSVGElement::GetEventNameForAttr(nsIAtom* aAttr)
1481 : {
1482 0 : if (aAttr == nsGkAtoms::onload)
1483 0 : return nsGkAtoms::onSVGLoad;
1484 0 : if (aAttr == nsGkAtoms::onunload)
1485 0 : return nsGkAtoms::onSVGUnload;
1486 0 : if (aAttr == nsGkAtoms::onabort)
1487 0 : return nsGkAtoms::onSVGAbort;
1488 0 : if (aAttr == nsGkAtoms::onerror)
1489 0 : return nsGkAtoms::onSVGError;
1490 0 : if (aAttr == nsGkAtoms::onresize)
1491 0 : return nsGkAtoms::onSVGResize;
1492 0 : if (aAttr == nsGkAtoms::onscroll)
1493 0 : return nsGkAtoms::onSVGScroll;
1494 0 : if (aAttr == nsGkAtoms::onzoom)
1495 0 : return nsGkAtoms::onSVGZoom;
1496 0 : if (aAttr == nsGkAtoms::onbegin)
1497 0 : return nsGkAtoms::onbeginEvent;
1498 0 : if (aAttr == nsGkAtoms::onrepeat)
1499 0 : return nsGkAtoms::onrepeatEvent;
1500 0 : if (aAttr == nsGkAtoms::onend)
1501 0 : return nsGkAtoms::onendEvent;
1502 :
1503 0 : return aAttr;
1504 : }
1505 :
1506 : nsSVGSVGElement *
1507 0 : nsSVGElement::GetCtx() const
1508 : {
1509 0 : nsIContent* ancestor = GetFlattenedTreeParent();
1510 :
1511 0 : while (ancestor && ancestor->IsSVG()) {
1512 0 : nsIAtom* tag = ancestor->Tag();
1513 0 : if (tag == nsGkAtoms::foreignObject) {
1514 0 : return nsnull;
1515 : }
1516 0 : if (tag == nsGkAtoms::svg) {
1517 0 : return static_cast<nsSVGSVGElement*>(ancestor);
1518 : }
1519 0 : ancestor = ancestor->GetFlattenedTreeParent();
1520 : }
1521 :
1522 : // we don't have an ancestor <svg> element...
1523 0 : return nsnull;
1524 : }
1525 :
1526 : /* virtual */ gfxMatrix
1527 0 : nsSVGElement::PrependLocalTransformsTo(const gfxMatrix &aMatrix,
1528 : TransformTypes aWhich) const
1529 : {
1530 0 : return aMatrix;
1531 : }
1532 :
1533 : nsSVGElement::LengthAttributesInfo
1534 0 : nsSVGElement::GetLengthInfo()
1535 : {
1536 0 : return LengthAttributesInfo(nsnull, nsnull, 0);
1537 : }
1538 :
1539 0 : void nsSVGElement::LengthAttributesInfo::Reset(PRUint8 aAttrEnum)
1540 : {
1541 0 : mLengths[aAttrEnum].Init(mLengthInfo[aAttrEnum].mCtxType,
1542 : aAttrEnum,
1543 0 : mLengthInfo[aAttrEnum].mDefaultValue,
1544 0 : mLengthInfo[aAttrEnum].mDefaultUnitType);
1545 0 : }
1546 :
1547 : void
1548 0 : nsSVGElement::SetLength(nsIAtom* aName, const nsSVGLength2 &aLength)
1549 : {
1550 0 : LengthAttributesInfo lengthInfo = GetLengthInfo();
1551 :
1552 0 : for (PRUint32 i = 0; i < lengthInfo.mLengthCount; i++) {
1553 0 : if (aName == *lengthInfo.mLengthInfo[i].mName) {
1554 0 : lengthInfo.mLengths[i] = aLength;
1555 0 : DidAnimateLength(i);
1556 0 : return;
1557 : }
1558 : }
1559 0 : NS_ABORT_IF_FALSE(false, "no length found to set");
1560 : }
1561 :
1562 : nsAttrValue
1563 0 : nsSVGElement::WillChangeLength(PRUint8 aAttrEnum)
1564 : {
1565 0 : return WillChangeValue(*GetLengthInfo().mLengthInfo[aAttrEnum].mName);
1566 : }
1567 :
1568 : void
1569 0 : nsSVGElement::DidChangeLength(PRUint8 aAttrEnum,
1570 : const nsAttrValue& aEmptyOrOldValue)
1571 : {
1572 0 : LengthAttributesInfo info = GetLengthInfo();
1573 :
1574 0 : NS_ASSERTION(info.mLengthCount > 0,
1575 : "DidChangeLength on element with no length attribs");
1576 0 : NS_ASSERTION(aAttrEnum < info.mLengthCount, "aAttrEnum out of range");
1577 :
1578 0 : nsAttrValue newValue;
1579 0 : newValue.SetTo(info.mLengths[aAttrEnum], nsnull);
1580 :
1581 0 : DidChangeValue(*info.mLengthInfo[aAttrEnum].mName, aEmptyOrOldValue,
1582 0 : newValue);
1583 0 : }
1584 :
1585 : void
1586 0 : nsSVGElement::DidAnimateLength(PRUint8 aAttrEnum)
1587 : {
1588 0 : nsIFrame* frame = GetPrimaryFrame();
1589 :
1590 0 : if (frame) {
1591 0 : LengthAttributesInfo info = GetLengthInfo();
1592 : frame->AttributeChanged(kNameSpaceID_None,
1593 0 : *info.mLengthInfo[aAttrEnum].mName,
1594 0 : nsIDOMMutationEvent::MODIFICATION);
1595 : }
1596 0 : }
1597 :
1598 : nsSVGLength2*
1599 0 : nsSVGElement::GetAnimatedLength(const nsIAtom *aAttrName)
1600 : {
1601 0 : LengthAttributesInfo lengthInfo = GetLengthInfo();
1602 :
1603 0 : for (PRUint32 i = 0; i < lengthInfo.mLengthCount; i++) {
1604 0 : if (aAttrName == *lengthInfo.mLengthInfo[i].mName) {
1605 0 : return &lengthInfo.mLengths[i];
1606 : }
1607 : }
1608 0 : NS_ABORT_IF_FALSE(false, "no matching length found");
1609 0 : return nsnull;
1610 : }
1611 :
1612 : void
1613 0 : nsSVGElement::GetAnimatedLengthValues(float *aFirst, ...)
1614 : {
1615 0 : LengthAttributesInfo info = GetLengthInfo();
1616 :
1617 0 : NS_ASSERTION(info.mLengthCount > 0,
1618 : "GetAnimatedLengthValues on element with no length attribs");
1619 :
1620 0 : nsSVGSVGElement *ctx = nsnull;
1621 :
1622 0 : float *f = aFirst;
1623 0 : PRUint32 i = 0;
1624 :
1625 : va_list args;
1626 0 : va_start(args, aFirst);
1627 :
1628 0 : while (f && i < info.mLengthCount) {
1629 0 : PRUint8 type = info.mLengths[i].GetSpecifiedUnitType();
1630 0 : if (!ctx) {
1631 0 : if (type != nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER &&
1632 : type != nsIDOMSVGLength::SVG_LENGTHTYPE_PX)
1633 0 : ctx = GetCtx();
1634 : }
1635 0 : if (type == nsIDOMSVGLength::SVG_LENGTHTYPE_EMS ||
1636 : type == nsIDOMSVGLength::SVG_LENGTHTYPE_EXS)
1637 0 : *f = info.mLengths[i++].GetAnimValue(this);
1638 : else
1639 0 : *f = info.mLengths[i++].GetAnimValue(ctx);
1640 0 : f = va_arg(args, float*);
1641 : }
1642 :
1643 0 : va_end(args);
1644 0 : }
1645 :
1646 : nsSVGElement::LengthListAttributesInfo
1647 0 : nsSVGElement::GetLengthListInfo()
1648 : {
1649 0 : return LengthListAttributesInfo(nsnull, nsnull, 0);
1650 : }
1651 :
1652 : void
1653 0 : nsSVGElement::LengthListAttributesInfo::Reset(PRUint8 aAttrEnum)
1654 : {
1655 0 : mLengthLists[aAttrEnum].ClearBaseValue(aAttrEnum);
1656 : // caller notifies
1657 0 : }
1658 :
1659 : nsAttrValue
1660 0 : nsSVGElement::WillChangeLengthList(PRUint8 aAttrEnum)
1661 : {
1662 0 : return WillChangeValue(*GetLengthListInfo().mLengthListInfo[aAttrEnum].mName);
1663 : }
1664 :
1665 : void
1666 0 : nsSVGElement::DidChangeLengthList(PRUint8 aAttrEnum,
1667 : const nsAttrValue& aEmptyOrOldValue)
1668 : {
1669 0 : LengthListAttributesInfo info = GetLengthListInfo();
1670 :
1671 0 : NS_ASSERTION(info.mLengthListCount > 0,
1672 : "DidChangeLengthList on element with no length list attribs");
1673 0 : NS_ASSERTION(aAttrEnum < info.mLengthListCount, "aAttrEnum out of range");
1674 :
1675 0 : nsAttrValue newValue;
1676 0 : newValue.SetTo(info.mLengthLists[aAttrEnum].GetBaseValue(), nsnull);
1677 :
1678 0 : DidChangeValue(*info.mLengthListInfo[aAttrEnum].mName, aEmptyOrOldValue,
1679 0 : newValue);
1680 0 : }
1681 :
1682 : void
1683 0 : nsSVGElement::DidAnimateLengthList(PRUint8 aAttrEnum)
1684 : {
1685 0 : nsIFrame* frame = GetPrimaryFrame();
1686 :
1687 0 : if (frame) {
1688 0 : LengthListAttributesInfo info = GetLengthListInfo();
1689 : frame->AttributeChanged(kNameSpaceID_None,
1690 0 : *info.mLengthListInfo[aAttrEnum].mName,
1691 0 : nsIDOMMutationEvent::MODIFICATION);
1692 : }
1693 0 : }
1694 :
1695 : void
1696 0 : nsSVGElement::GetAnimatedLengthListValues(SVGUserUnitList *aFirst, ...)
1697 : {
1698 0 : LengthListAttributesInfo info = GetLengthListInfo();
1699 :
1700 0 : NS_ASSERTION(info.mLengthListCount > 0,
1701 : "GetAnimatedLengthListValues on element with no length list attribs");
1702 :
1703 0 : SVGUserUnitList *list = aFirst;
1704 0 : PRUint32 i = 0;
1705 :
1706 : va_list args;
1707 0 : va_start(args, aFirst);
1708 :
1709 0 : while (list && i < info.mLengthListCount) {
1710 0 : list->Init(&(info.mLengthLists[i].GetAnimValue()), this, info.mLengthListInfo[i].mAxis);
1711 0 : ++i;
1712 0 : list = va_arg(args, SVGUserUnitList*);
1713 : }
1714 :
1715 0 : va_end(args);
1716 0 : }
1717 :
1718 : SVGAnimatedLengthList*
1719 0 : nsSVGElement::GetAnimatedLengthList(PRUint8 aAttrEnum)
1720 : {
1721 0 : LengthListAttributesInfo info = GetLengthListInfo();
1722 0 : if (aAttrEnum < info.mLengthListCount) {
1723 0 : return &(info.mLengthLists[aAttrEnum]);
1724 : }
1725 0 : NS_NOTREACHED("Bad attrEnum");
1726 0 : return nsnull;
1727 : }
1728 :
1729 :
1730 : nsSVGElement::NumberListAttributesInfo
1731 0 : nsSVGElement::GetNumberListInfo()
1732 : {
1733 0 : return NumberListAttributesInfo(nsnull, nsnull, 0);
1734 : }
1735 :
1736 : void
1737 0 : nsSVGElement::NumberListAttributesInfo::Reset(PRUint8 aAttrEnum)
1738 : {
1739 0 : NS_ABORT_IF_FALSE(aAttrEnum < mNumberListCount, "Bad attr enum");
1740 0 : mNumberLists[aAttrEnum].ClearBaseValue(aAttrEnum);
1741 : // caller notifies
1742 0 : }
1743 :
1744 : nsAttrValue
1745 0 : nsSVGElement::WillChangeNumberList(PRUint8 aAttrEnum)
1746 : {
1747 0 : return WillChangeValue(*GetNumberListInfo().mNumberListInfo[aAttrEnum].mName);
1748 : }
1749 :
1750 : void
1751 0 : nsSVGElement::DidChangeNumberList(PRUint8 aAttrEnum,
1752 : const nsAttrValue& aEmptyOrOldValue)
1753 : {
1754 0 : NumberListAttributesInfo info = GetNumberListInfo();
1755 :
1756 0 : NS_ABORT_IF_FALSE(info.mNumberListCount > 0,
1757 : "DidChangeNumberList on element with no number list attribs");
1758 0 : NS_ABORT_IF_FALSE(aAttrEnum < info.mNumberListCount,
1759 : "aAttrEnum out of range");
1760 :
1761 0 : nsAttrValue newValue;
1762 0 : newValue.SetTo(info.mNumberLists[aAttrEnum].GetBaseValue(), nsnull);
1763 :
1764 0 : DidChangeValue(*info.mNumberListInfo[aAttrEnum].mName, aEmptyOrOldValue,
1765 0 : newValue);
1766 0 : }
1767 :
1768 : void
1769 0 : nsSVGElement::DidAnimateNumberList(PRUint8 aAttrEnum)
1770 : {
1771 0 : nsIFrame* frame = GetPrimaryFrame();
1772 :
1773 0 : if (frame) {
1774 0 : NumberListAttributesInfo info = GetNumberListInfo();
1775 0 : NS_ABORT_IF_FALSE(aAttrEnum < info.mNumberListCount, "aAttrEnum out of range");
1776 :
1777 : frame->AttributeChanged(kNameSpaceID_None,
1778 0 : *info.mNumberListInfo[aAttrEnum].mName,
1779 0 : nsIDOMMutationEvent::MODIFICATION);
1780 : }
1781 0 : }
1782 :
1783 : SVGAnimatedNumberList*
1784 0 : nsSVGElement::GetAnimatedNumberList(PRUint8 aAttrEnum)
1785 : {
1786 0 : NumberListAttributesInfo info = GetNumberListInfo();
1787 0 : if (aAttrEnum < info.mNumberListCount) {
1788 0 : return &(info.mNumberLists[aAttrEnum]);
1789 : }
1790 0 : NS_ABORT_IF_FALSE(false, "Bad attrEnum");
1791 0 : return nsnull;
1792 : }
1793 :
1794 : SVGAnimatedNumberList*
1795 0 : nsSVGElement::GetAnimatedNumberList(nsIAtom *aAttrName)
1796 : {
1797 0 : NumberListAttributesInfo info = GetNumberListInfo();
1798 0 : for (PRUint32 i = 0; i < info.mNumberListCount; i++) {
1799 0 : if (aAttrName == *info.mNumberListInfo[i].mName) {
1800 0 : return &info.mNumberLists[i];
1801 : }
1802 : }
1803 0 : NS_ABORT_IF_FALSE(false, "Bad caller");
1804 0 : return nsnull;
1805 : }
1806 :
1807 : nsAttrValue
1808 0 : nsSVGElement::WillChangePointList()
1809 : {
1810 0 : NS_ABORT_IF_FALSE(GetPointListAttrName(),
1811 : "Changing non-existent point list?");
1812 0 : return WillChangeValue(GetPointListAttrName());
1813 : }
1814 :
1815 : void
1816 0 : nsSVGElement::DidChangePointList(const nsAttrValue& aEmptyOrOldValue)
1817 : {
1818 0 : NS_ABORT_IF_FALSE(GetPointListAttrName(),
1819 : "Changing non-existent point list?");
1820 :
1821 0 : nsAttrValue newValue;
1822 0 : newValue.SetTo(GetAnimatedPointList()->GetBaseValue(), nsnull);
1823 :
1824 0 : DidChangeValue(GetPointListAttrName(), aEmptyOrOldValue, newValue);
1825 0 : }
1826 :
1827 : void
1828 0 : nsSVGElement::DidAnimatePointList()
1829 : {
1830 0 : NS_ABORT_IF_FALSE(GetPointListAttrName(),
1831 : "Animating non-existent path data?");
1832 :
1833 0 : nsIFrame* frame = GetPrimaryFrame();
1834 :
1835 0 : if (frame) {
1836 : frame->AttributeChanged(kNameSpaceID_None,
1837 0 : GetPointListAttrName(),
1838 0 : nsIDOMMutationEvent::MODIFICATION);
1839 : }
1840 0 : }
1841 :
1842 : nsAttrValue
1843 0 : nsSVGElement::WillChangePathSegList()
1844 : {
1845 0 : NS_ABORT_IF_FALSE(GetPathDataAttrName(),
1846 : "Changing non-existent path seg list?");
1847 0 : return WillChangeValue(GetPathDataAttrName());
1848 : }
1849 :
1850 : void
1851 0 : nsSVGElement::DidChangePathSegList(const nsAttrValue& aEmptyOrOldValue)
1852 : {
1853 0 : NS_ABORT_IF_FALSE(GetPathDataAttrName(),
1854 : "Changing non-existent path seg list?");
1855 :
1856 0 : nsAttrValue newValue;
1857 0 : newValue.SetTo(GetAnimPathSegList()->GetBaseValue(), nsnull);
1858 :
1859 0 : DidChangeValue(GetPathDataAttrName(), aEmptyOrOldValue, newValue);
1860 0 : }
1861 :
1862 : void
1863 0 : nsSVGElement::DidAnimatePathSegList()
1864 : {
1865 0 : NS_ABORT_IF_FALSE(GetPathDataAttrName(),
1866 : "Animating non-existent path data?");
1867 :
1868 0 : nsIFrame* frame = GetPrimaryFrame();
1869 :
1870 0 : if (frame) {
1871 : frame->AttributeChanged(kNameSpaceID_None,
1872 0 : GetPathDataAttrName(),
1873 0 : nsIDOMMutationEvent::MODIFICATION);
1874 : }
1875 0 : }
1876 :
1877 : nsSVGElement::NumberAttributesInfo
1878 0 : nsSVGElement::GetNumberInfo()
1879 : {
1880 0 : return NumberAttributesInfo(nsnull, nsnull, 0);
1881 : }
1882 :
1883 0 : void nsSVGElement::NumberAttributesInfo::Reset(PRUint8 aAttrEnum)
1884 : {
1885 : mNumbers[aAttrEnum].Init(aAttrEnum,
1886 0 : mNumberInfo[aAttrEnum].mDefaultValue);
1887 0 : }
1888 :
1889 : void
1890 0 : nsSVGElement::DidChangeNumber(PRUint8 aAttrEnum)
1891 : {
1892 0 : NumberAttributesInfo info = GetNumberInfo();
1893 :
1894 0 : NS_ASSERTION(info.mNumberCount > 0,
1895 : "DidChangeNumber on element with no number attribs");
1896 0 : NS_ASSERTION(aAttrEnum < info.mNumberCount, "aAttrEnum out of range");
1897 :
1898 0 : nsAttrValue attrValue;
1899 0 : attrValue.SetTo(info.mNumbers[aAttrEnum].GetBaseValue(), nsnull);
1900 :
1901 0 : SetParsedAttr(kNameSpaceID_None, *info.mNumberInfo[aAttrEnum].mName, nsnull,
1902 0 : attrValue, true);
1903 0 : }
1904 :
1905 : void
1906 0 : nsSVGElement::DidAnimateNumber(PRUint8 aAttrEnum)
1907 : {
1908 0 : nsIFrame* frame = GetPrimaryFrame();
1909 :
1910 0 : if (frame) {
1911 0 : NumberAttributesInfo info = GetNumberInfo();
1912 : frame->AttributeChanged(kNameSpaceID_None,
1913 0 : *info.mNumberInfo[aAttrEnum].mName,
1914 0 : nsIDOMMutationEvent::MODIFICATION);
1915 : }
1916 0 : }
1917 :
1918 : void
1919 0 : nsSVGElement::GetAnimatedNumberValues(float *aFirst, ...)
1920 : {
1921 0 : NumberAttributesInfo info = GetNumberInfo();
1922 :
1923 0 : NS_ASSERTION(info.mNumberCount > 0,
1924 : "GetAnimatedNumberValues on element with no number attribs");
1925 :
1926 0 : float *f = aFirst;
1927 0 : PRUint32 i = 0;
1928 :
1929 : va_list args;
1930 0 : va_start(args, aFirst);
1931 :
1932 0 : while (f && i < info.mNumberCount) {
1933 0 : *f = info.mNumbers[i++].GetAnimValue();
1934 0 : f = va_arg(args, float*);
1935 : }
1936 0 : va_end(args);
1937 0 : }
1938 :
1939 : nsSVGElement::NumberPairAttributesInfo
1940 0 : nsSVGElement::GetNumberPairInfo()
1941 : {
1942 0 : return NumberPairAttributesInfo(nsnull, nsnull, 0);
1943 : }
1944 :
1945 0 : void nsSVGElement::NumberPairAttributesInfo::Reset(PRUint8 aAttrEnum)
1946 : {
1947 : mNumberPairs[aAttrEnum].Init(aAttrEnum,
1948 0 : mNumberPairInfo[aAttrEnum].mDefaultValue1,
1949 0 : mNumberPairInfo[aAttrEnum].mDefaultValue2);
1950 0 : }
1951 :
1952 : nsAttrValue
1953 0 : nsSVGElement::WillChangeNumberPair(PRUint8 aAttrEnum)
1954 : {
1955 0 : return WillChangeValue(*GetNumberPairInfo().mNumberPairInfo[aAttrEnum].mName);
1956 : }
1957 :
1958 : void
1959 0 : nsSVGElement::DidChangeNumberPair(PRUint8 aAttrEnum,
1960 : const nsAttrValue& aEmptyOrOldValue)
1961 : {
1962 0 : NumberPairAttributesInfo info = GetNumberPairInfo();
1963 :
1964 0 : NS_ASSERTION(info.mNumberPairCount > 0,
1965 : "DidChangePairNumber on element with no number pair attribs");
1966 0 : NS_ASSERTION(aAttrEnum < info.mNumberPairCount, "aAttrEnum out of range");
1967 :
1968 0 : nsAttrValue newValue;
1969 0 : newValue.SetTo(info.mNumberPairs[aAttrEnum], nsnull);
1970 :
1971 0 : DidChangeValue(*info.mNumberPairInfo[aAttrEnum].mName, aEmptyOrOldValue,
1972 0 : newValue);
1973 0 : }
1974 :
1975 : void
1976 0 : nsSVGElement::DidAnimateNumberPair(PRUint8 aAttrEnum)
1977 : {
1978 0 : nsIFrame* frame = GetPrimaryFrame();
1979 :
1980 0 : if (frame) {
1981 0 : NumberPairAttributesInfo info = GetNumberPairInfo();
1982 : frame->AttributeChanged(kNameSpaceID_None,
1983 0 : *info.mNumberPairInfo[aAttrEnum].mName,
1984 0 : nsIDOMMutationEvent::MODIFICATION);
1985 : }
1986 0 : }
1987 :
1988 : nsSVGElement::IntegerAttributesInfo
1989 0 : nsSVGElement::GetIntegerInfo()
1990 : {
1991 0 : return IntegerAttributesInfo(nsnull, nsnull, 0);
1992 : }
1993 :
1994 0 : void nsSVGElement::IntegerAttributesInfo::Reset(PRUint8 aAttrEnum)
1995 : {
1996 : mIntegers[aAttrEnum].Init(aAttrEnum,
1997 0 : mIntegerInfo[aAttrEnum].mDefaultValue);
1998 0 : }
1999 :
2000 : void
2001 0 : nsSVGElement::DidChangeInteger(PRUint8 aAttrEnum)
2002 : {
2003 0 : IntegerAttributesInfo info = GetIntegerInfo();
2004 :
2005 0 : NS_ASSERTION(info.mIntegerCount > 0,
2006 : "DidChangeInteger on element with no integer attribs");
2007 0 : NS_ASSERTION(aAttrEnum < info.mIntegerCount, "aAttrEnum out of range");
2008 :
2009 0 : nsAttrValue attrValue;
2010 0 : attrValue.SetTo(info.mIntegers[aAttrEnum].GetBaseValue(), nsnull);
2011 :
2012 0 : SetParsedAttr(kNameSpaceID_None, *info.mIntegerInfo[aAttrEnum].mName, nsnull,
2013 0 : attrValue, true);
2014 0 : }
2015 :
2016 : void
2017 0 : nsSVGElement::DidAnimateInteger(PRUint8 aAttrEnum)
2018 : {
2019 0 : nsIFrame* frame = GetPrimaryFrame();
2020 :
2021 0 : if (frame) {
2022 0 : IntegerAttributesInfo info = GetIntegerInfo();
2023 : frame->AttributeChanged(kNameSpaceID_None,
2024 0 : *info.mIntegerInfo[aAttrEnum].mName,
2025 0 : nsIDOMMutationEvent::MODIFICATION);
2026 : }
2027 0 : }
2028 :
2029 : void
2030 0 : nsSVGElement::GetAnimatedIntegerValues(PRInt32 *aFirst, ...)
2031 : {
2032 0 : IntegerAttributesInfo info = GetIntegerInfo();
2033 :
2034 0 : NS_ASSERTION(info.mIntegerCount > 0,
2035 : "GetAnimatedIntegerValues on element with no integer attribs");
2036 :
2037 0 : PRInt32 *n = aFirst;
2038 0 : PRUint32 i = 0;
2039 :
2040 : va_list args;
2041 0 : va_start(args, aFirst);
2042 :
2043 0 : while (n && i < info.mIntegerCount) {
2044 0 : *n = info.mIntegers[i++].GetAnimValue();
2045 0 : n = va_arg(args, PRInt32*);
2046 : }
2047 0 : va_end(args);
2048 0 : }
2049 :
2050 : nsSVGElement::IntegerPairAttributesInfo
2051 0 : nsSVGElement::GetIntegerPairInfo()
2052 : {
2053 0 : return IntegerPairAttributesInfo(nsnull, nsnull, 0);
2054 : }
2055 :
2056 0 : void nsSVGElement::IntegerPairAttributesInfo::Reset(PRUint8 aAttrEnum)
2057 : {
2058 : mIntegerPairs[aAttrEnum].Init(aAttrEnum,
2059 0 : mIntegerPairInfo[aAttrEnum].mDefaultValue1,
2060 0 : mIntegerPairInfo[aAttrEnum].mDefaultValue2);
2061 0 : }
2062 :
2063 : nsAttrValue
2064 0 : nsSVGElement::WillChangeIntegerPair(PRUint8 aAttrEnum)
2065 : {
2066 : return WillChangeValue(
2067 0 : *GetIntegerPairInfo().mIntegerPairInfo[aAttrEnum].mName);
2068 : }
2069 :
2070 : void
2071 0 : nsSVGElement::DidChangeIntegerPair(PRUint8 aAttrEnum,
2072 : const nsAttrValue& aEmptyOrOldValue)
2073 : {
2074 0 : IntegerPairAttributesInfo info = GetIntegerPairInfo();
2075 :
2076 0 : NS_ASSERTION(info.mIntegerPairCount > 0,
2077 : "DidChangeIntegerPair on element with no integer pair attribs");
2078 0 : NS_ASSERTION(aAttrEnum < info.mIntegerPairCount, "aAttrEnum out of range");
2079 :
2080 0 : nsAttrValue newValue;
2081 0 : newValue.SetTo(info.mIntegerPairs[aAttrEnum], nsnull);
2082 :
2083 0 : DidChangeValue(*info.mIntegerPairInfo[aAttrEnum].mName, aEmptyOrOldValue,
2084 0 : newValue);
2085 0 : }
2086 :
2087 : void
2088 0 : nsSVGElement::DidAnimateIntegerPair(PRUint8 aAttrEnum)
2089 : {
2090 0 : nsIFrame* frame = GetPrimaryFrame();
2091 :
2092 0 : if (frame) {
2093 0 : IntegerPairAttributesInfo info = GetIntegerPairInfo();
2094 : frame->AttributeChanged(kNameSpaceID_None,
2095 0 : *info.mIntegerPairInfo[aAttrEnum].mName,
2096 0 : nsIDOMMutationEvent::MODIFICATION);
2097 : }
2098 0 : }
2099 :
2100 : nsSVGElement::AngleAttributesInfo
2101 0 : nsSVGElement::GetAngleInfo()
2102 : {
2103 0 : return AngleAttributesInfo(nsnull, nsnull, 0);
2104 : }
2105 :
2106 0 : void nsSVGElement::AngleAttributesInfo::Reset(PRUint8 aAttrEnum)
2107 : {
2108 : mAngles[aAttrEnum].Init(aAttrEnum,
2109 0 : mAngleInfo[aAttrEnum].mDefaultValue,
2110 0 : mAngleInfo[aAttrEnum].mDefaultUnitType);
2111 0 : }
2112 :
2113 : nsAttrValue
2114 0 : nsSVGElement::WillChangeAngle(PRUint8 aAttrEnum)
2115 : {
2116 0 : return WillChangeValue(*GetAngleInfo().mAngleInfo[aAttrEnum].mName);
2117 : }
2118 :
2119 : void
2120 0 : nsSVGElement::DidChangeAngle(PRUint8 aAttrEnum,
2121 : const nsAttrValue& aEmptyOrOldValue)
2122 : {
2123 0 : AngleAttributesInfo info = GetAngleInfo();
2124 :
2125 0 : NS_ASSERTION(info.mAngleCount > 0,
2126 : "DidChangeAngle on element with no angle attribs");
2127 0 : NS_ASSERTION(aAttrEnum < info.mAngleCount, "aAttrEnum out of range");
2128 :
2129 0 : nsAttrValue newValue;
2130 0 : newValue.SetTo(info.mAngles[aAttrEnum], nsnull);
2131 :
2132 0 : DidChangeValue(*info.mAngleInfo[aAttrEnum].mName, aEmptyOrOldValue, newValue);
2133 0 : }
2134 :
2135 : void
2136 0 : nsSVGElement::DidAnimateAngle(PRUint8 aAttrEnum)
2137 : {
2138 0 : nsIFrame* frame = GetPrimaryFrame();
2139 :
2140 0 : if (frame) {
2141 0 : AngleAttributesInfo info = GetAngleInfo();
2142 : frame->AttributeChanged(kNameSpaceID_None,
2143 0 : *info.mAngleInfo[aAttrEnum].mName,
2144 0 : nsIDOMMutationEvent::MODIFICATION);
2145 : }
2146 0 : }
2147 :
2148 : nsSVGElement::BooleanAttributesInfo
2149 0 : nsSVGElement::GetBooleanInfo()
2150 : {
2151 0 : return BooleanAttributesInfo(nsnull, nsnull, 0);
2152 : }
2153 :
2154 0 : void nsSVGElement::BooleanAttributesInfo::Reset(PRUint8 aAttrEnum)
2155 : {
2156 : mBooleans[aAttrEnum].Init(aAttrEnum,
2157 0 : mBooleanInfo[aAttrEnum].mDefaultValue);
2158 0 : }
2159 :
2160 : void
2161 0 : nsSVGElement::DidChangeBoolean(PRUint8 aAttrEnum)
2162 : {
2163 0 : BooleanAttributesInfo info = GetBooleanInfo();
2164 :
2165 0 : NS_ASSERTION(info.mBooleanCount > 0,
2166 : "DidChangeBoolean on element with no boolean attribs");
2167 0 : NS_ASSERTION(aAttrEnum < info.mBooleanCount, "aAttrEnum out of range");
2168 :
2169 0 : nsAttrValue attrValue(info.mBooleans[aAttrEnum].GetBaseValueAtom());
2170 0 : SetParsedAttr(kNameSpaceID_None, *info.mBooleanInfo[aAttrEnum].mName, nsnull,
2171 0 : attrValue, true);
2172 0 : }
2173 :
2174 : void
2175 0 : nsSVGElement::DidAnimateBoolean(PRUint8 aAttrEnum)
2176 : {
2177 0 : nsIFrame* frame = GetPrimaryFrame();
2178 :
2179 0 : if (frame) {
2180 0 : BooleanAttributesInfo info = GetBooleanInfo();
2181 : frame->AttributeChanged(kNameSpaceID_None,
2182 0 : *info.mBooleanInfo[aAttrEnum].mName,
2183 0 : nsIDOMMutationEvent::MODIFICATION);
2184 : }
2185 0 : }
2186 :
2187 : nsSVGElement::EnumAttributesInfo
2188 0 : nsSVGElement::GetEnumInfo()
2189 : {
2190 0 : return EnumAttributesInfo(nsnull, nsnull, 0);
2191 : }
2192 :
2193 0 : void nsSVGElement::EnumAttributesInfo::Reset(PRUint8 aAttrEnum)
2194 : {
2195 : mEnums[aAttrEnum].Init(aAttrEnum,
2196 0 : mEnumInfo[aAttrEnum].mDefaultValue);
2197 0 : }
2198 :
2199 : void
2200 0 : nsSVGElement::DidChangeEnum(PRUint8 aAttrEnum)
2201 : {
2202 0 : EnumAttributesInfo info = GetEnumInfo();
2203 :
2204 0 : NS_ASSERTION(info.mEnumCount > 0,
2205 : "DidChangeEnum on element with no enum attribs");
2206 0 : NS_ASSERTION(aAttrEnum < info.mEnumCount, "aAttrEnum out of range");
2207 :
2208 0 : nsAttrValue attrValue(info.mEnums[aAttrEnum].GetBaseValueAtom(this));
2209 0 : SetParsedAttr(kNameSpaceID_None, *info.mEnumInfo[aAttrEnum].mName, nsnull,
2210 0 : attrValue, true);
2211 0 : }
2212 :
2213 : void
2214 0 : nsSVGElement::DidAnimateEnum(PRUint8 aAttrEnum)
2215 : {
2216 0 : nsIFrame* frame = GetPrimaryFrame();
2217 :
2218 0 : if (frame) {
2219 0 : EnumAttributesInfo info = GetEnumInfo();
2220 : frame->AttributeChanged(kNameSpaceID_None,
2221 0 : *info.mEnumInfo[aAttrEnum].mName,
2222 0 : nsIDOMMutationEvent::MODIFICATION);
2223 : }
2224 0 : }
2225 :
2226 : nsSVGViewBox *
2227 0 : nsSVGElement::GetViewBox()
2228 : {
2229 0 : return nsnull;
2230 : }
2231 :
2232 : nsAttrValue
2233 0 : nsSVGElement::WillChangeViewBox()
2234 : {
2235 0 : return WillChangeValue(nsGkAtoms::viewBox);
2236 : }
2237 :
2238 : void
2239 0 : nsSVGElement::DidChangeViewBox(const nsAttrValue& aEmptyOrOldValue)
2240 : {
2241 0 : nsSVGViewBox *viewBox = GetViewBox();
2242 :
2243 0 : NS_ASSERTION(viewBox, "DidChangeViewBox on element with no viewBox attrib");
2244 :
2245 0 : nsAttrValue newValue;
2246 0 : newValue.SetTo(*viewBox, nsnull);
2247 :
2248 0 : DidChangeValue(nsGkAtoms::viewBox, aEmptyOrOldValue, newValue);
2249 0 : }
2250 :
2251 : void
2252 0 : nsSVGElement::DidAnimateViewBox()
2253 : {
2254 0 : nsIFrame* frame = GetPrimaryFrame();
2255 :
2256 0 : if (frame) {
2257 : frame->AttributeChanged(kNameSpaceID_None,
2258 : nsGkAtoms::viewBox,
2259 0 : nsIDOMMutationEvent::MODIFICATION);
2260 : }
2261 0 : }
2262 :
2263 : SVGAnimatedPreserveAspectRatio *
2264 0 : nsSVGElement::GetPreserveAspectRatio()
2265 : {
2266 0 : return nsnull;
2267 : }
2268 :
2269 : nsAttrValue
2270 0 : nsSVGElement::WillChangePreserveAspectRatio()
2271 : {
2272 0 : return WillChangeValue(nsGkAtoms::preserveAspectRatio);
2273 : }
2274 :
2275 : void
2276 0 : nsSVGElement::DidChangePreserveAspectRatio(const nsAttrValue& aEmptyOrOldValue)
2277 : {
2278 : SVGAnimatedPreserveAspectRatio *preserveAspectRatio =
2279 0 : GetPreserveAspectRatio();
2280 :
2281 0 : NS_ASSERTION(preserveAspectRatio,
2282 : "DidChangePreserveAspectRatio on element with no "
2283 : "preserveAspectRatio attrib");
2284 :
2285 0 : nsAttrValue newValue;
2286 0 : newValue.SetTo(*preserveAspectRatio, nsnull);
2287 :
2288 0 : DidChangeValue(nsGkAtoms::preserveAspectRatio, aEmptyOrOldValue, newValue);
2289 0 : }
2290 :
2291 : void
2292 0 : nsSVGElement::DidAnimatePreserveAspectRatio()
2293 : {
2294 0 : nsIFrame* frame = GetPrimaryFrame();
2295 :
2296 0 : if (frame) {
2297 : frame->AttributeChanged(kNameSpaceID_None,
2298 : nsGkAtoms::preserveAspectRatio,
2299 0 : nsIDOMMutationEvent::MODIFICATION);
2300 : }
2301 0 : }
2302 :
2303 : nsAttrValue
2304 0 : nsSVGElement::WillChangeTransformList()
2305 : {
2306 0 : return WillChangeValue(GetTransformListAttrName());
2307 : }
2308 :
2309 : void
2310 0 : nsSVGElement::DidChangeTransformList(const nsAttrValue& aEmptyOrOldValue)
2311 : {
2312 0 : NS_ABORT_IF_FALSE(GetTransformListAttrName(),
2313 : "Changing non-existent transform list?");
2314 :
2315 0 : nsAttrValue newValue;
2316 0 : newValue.SetTo(GetAnimatedTransformList()->GetBaseValue(), nsnull);
2317 :
2318 0 : DidChangeValue(GetTransformListAttrName(), aEmptyOrOldValue, newValue);
2319 0 : }
2320 :
2321 : void
2322 0 : nsSVGElement::DidAnimateTransformList()
2323 : {
2324 0 : NS_ABORT_IF_FALSE(GetTransformListAttrName(),
2325 : "Animating non-existent transform data?");
2326 :
2327 0 : nsIFrame* frame = GetPrimaryFrame();
2328 :
2329 0 : if (frame) {
2330 : frame->AttributeChanged(kNameSpaceID_None,
2331 0 : GetTransformListAttrName(),
2332 0 : nsIDOMMutationEvent::MODIFICATION);
2333 : }
2334 0 : }
2335 :
2336 : nsSVGElement::StringAttributesInfo
2337 0 : nsSVGElement::GetStringInfo()
2338 : {
2339 0 : return StringAttributesInfo(nsnull, nsnull, 0);
2340 : }
2341 :
2342 0 : void nsSVGElement::StringAttributesInfo::Reset(PRUint8 aAttrEnum)
2343 : {
2344 0 : mStrings[aAttrEnum].Init(aAttrEnum);
2345 0 : }
2346 :
2347 0 : void nsSVGElement::GetStringBaseValue(PRUint8 aAttrEnum, nsAString& aResult) const
2348 : {
2349 0 : nsSVGElement::StringAttributesInfo info = const_cast<nsSVGElement*>(this)->GetStringInfo();
2350 :
2351 0 : NS_ASSERTION(info.mStringCount > 0,
2352 : "GetBaseValue on element with no string attribs");
2353 :
2354 0 : NS_ASSERTION(aAttrEnum < info.mStringCount, "aAttrEnum out of range");
2355 :
2356 0 : GetAttr(info.mStringInfo[aAttrEnum].mNamespaceID,
2357 0 : *info.mStringInfo[aAttrEnum].mName, aResult);
2358 0 : }
2359 :
2360 0 : void nsSVGElement::SetStringBaseValue(PRUint8 aAttrEnum, const nsAString& aValue)
2361 : {
2362 0 : nsSVGElement::StringAttributesInfo info = GetStringInfo();
2363 :
2364 0 : NS_ASSERTION(info.mStringCount > 0,
2365 : "SetBaseValue on element with no string attribs");
2366 :
2367 0 : NS_ASSERTION(aAttrEnum < info.mStringCount, "aAttrEnum out of range");
2368 :
2369 0 : SetAttr(info.mStringInfo[aAttrEnum].mNamespaceID,
2370 0 : *info.mStringInfo[aAttrEnum].mName, aValue, true);
2371 0 : }
2372 :
2373 : void
2374 0 : nsSVGElement::DidAnimateString(PRUint8 aAttrEnum)
2375 : {
2376 0 : nsIFrame* frame = GetPrimaryFrame();
2377 :
2378 0 : if (frame) {
2379 0 : StringAttributesInfo info = GetStringInfo();
2380 0 : frame->AttributeChanged(info.mStringInfo[aAttrEnum].mNamespaceID,
2381 0 : *info.mStringInfo[aAttrEnum].mName,
2382 0 : nsIDOMMutationEvent::MODIFICATION);
2383 : }
2384 0 : }
2385 :
2386 : nsSVGElement::StringListAttributesInfo
2387 0 : nsSVGElement::GetStringListInfo()
2388 : {
2389 0 : return StringListAttributesInfo(nsnull, nsnull, 0);
2390 : }
2391 :
2392 : nsAttrValue
2393 0 : nsSVGElement::WillChangeStringList(bool aIsConditionalProcessingAttribute,
2394 : PRUint8 aAttrEnum)
2395 : {
2396 : nsIAtom* name;
2397 0 : if (aIsConditionalProcessingAttribute) {
2398 0 : nsCOMPtr<DOMSVGTests> tests(do_QueryInterface(this));
2399 0 : name = tests->GetAttrName(aAttrEnum);
2400 : } else {
2401 0 : name = *GetStringListInfo().mStringListInfo[aAttrEnum].mName;
2402 : }
2403 0 : return WillChangeValue(name);
2404 : }
2405 :
2406 : void
2407 0 : nsSVGElement::DidChangeStringList(bool aIsConditionalProcessingAttribute,
2408 : PRUint8 aAttrEnum,
2409 : const nsAttrValue& aEmptyOrOldValue)
2410 : {
2411 : nsIAtom* name;
2412 0 : nsAttrValue newValue;
2413 0 : nsCOMPtr<DOMSVGTests> tests;
2414 :
2415 0 : if (aIsConditionalProcessingAttribute) {
2416 0 : tests = do_QueryInterface(this);
2417 0 : name = tests->GetAttrName(aAttrEnum);
2418 0 : tests->GetAttrValue(aAttrEnum, newValue);
2419 : } else {
2420 0 : StringListAttributesInfo info = GetStringListInfo();
2421 :
2422 0 : NS_ASSERTION(info.mStringListCount > 0,
2423 : "DidChangeStringList on element with no string list attribs");
2424 0 : NS_ASSERTION(aAttrEnum < info.mStringListCount, "aAttrEnum out of range");
2425 :
2426 0 : name = *info.mStringListInfo[aAttrEnum].mName;
2427 0 : newValue.SetTo(info.mStringLists[aAttrEnum], nsnull);
2428 : }
2429 :
2430 0 : DidChangeValue(name, aEmptyOrOldValue, newValue);
2431 :
2432 0 : if (aIsConditionalProcessingAttribute) {
2433 0 : tests->MaybeInvalidate();
2434 : }
2435 0 : }
2436 :
2437 : void
2438 0 : nsSVGElement::StringListAttributesInfo::Reset(PRUint8 aAttrEnum)
2439 : {
2440 0 : mStringLists[aAttrEnum].Clear();
2441 : // caller notifies
2442 0 : }
2443 :
2444 : nsresult
2445 0 : nsSVGElement::ReportAttributeParseFailure(nsIDocument* aDocument,
2446 : nsIAtom* aAttribute,
2447 : const nsAString& aValue)
2448 : {
2449 0 : const nsAFlatString& attributeValue = PromiseFlatString(aValue);
2450 0 : const PRUnichar *strings[] = { aAttribute->GetUTF16String(),
2451 0 : attributeValue.get() };
2452 : return nsSVGUtils::ReportToConsole(aDocument,
2453 : "AttributeParseWarning",
2454 0 : strings, ArrayLength(strings));
2455 : }
2456 :
2457 : void
2458 0 : nsSVGElement::RecompileScriptEventListeners()
2459 : {
2460 0 : PRInt32 i, count = mAttrsAndChildren.AttrCount();
2461 0 : for (i = 0; i < count; ++i) {
2462 0 : const nsAttrName *name = mAttrsAndChildren.AttrNameAt(i);
2463 :
2464 : // Eventlistenener-attributes are always in the null namespace
2465 0 : if (!name->IsAtom()) {
2466 0 : continue;
2467 : }
2468 :
2469 0 : nsIAtom *attr = name->Atom();
2470 0 : if (!IsEventName(attr)) {
2471 0 : continue;
2472 : }
2473 :
2474 0 : nsAutoString value;
2475 0 : GetAttr(kNameSpaceID_None, attr, value);
2476 0 : AddScriptEventListener(GetEventNameForAttr(attr), value, true);
2477 : }
2478 0 : }
2479 :
2480 : nsISMILAttr*
2481 0 : nsSVGElement::GetAnimatedAttr(PRInt32 aNamespaceID, nsIAtom* aName)
2482 : {
2483 0 : if (aNamespaceID == kNameSpaceID_None) {
2484 : // Transforms:
2485 0 : if (GetTransformListAttrName() == aName) {
2486 0 : SVGAnimatedTransformList* transformList = GetAnimatedTransformList();
2487 0 : return transformList ? transformList->ToSMILAttr(this) : nsnull;
2488 : }
2489 :
2490 : // Motion (fake 'attribute' for animateMotion)
2491 0 : if (aName == nsGkAtoms::mozAnimateMotionDummyAttr) {
2492 0 : return new SVGMotionSMILAttr(this);
2493 : }
2494 :
2495 : // Lengths:
2496 0 : LengthAttributesInfo info = GetLengthInfo();
2497 0 : for (PRUint32 i = 0; i < info.mLengthCount; i++) {
2498 0 : if (aName == *info.mLengthInfo[i].mName) {
2499 0 : return info.mLengths[i].ToSMILAttr(this);
2500 : }
2501 : }
2502 :
2503 : // Numbers:
2504 : {
2505 0 : NumberAttributesInfo info = GetNumberInfo();
2506 0 : for (PRUint32 i = 0; i < info.mNumberCount; i++) {
2507 0 : if (aName == *info.mNumberInfo[i].mName) {
2508 0 : return info.mNumbers[i].ToSMILAttr(this);
2509 : }
2510 : }
2511 : }
2512 :
2513 : // Number Pairs:
2514 : {
2515 0 : NumberPairAttributesInfo info = GetNumberPairInfo();
2516 0 : for (PRUint32 i = 0; i < info.mNumberPairCount; i++) {
2517 0 : if (aName == *info.mNumberPairInfo[i].mName) {
2518 0 : return info.mNumberPairs[i].ToSMILAttr(this);
2519 : }
2520 : }
2521 : }
2522 :
2523 : // Integers:
2524 : {
2525 0 : IntegerAttributesInfo info = GetIntegerInfo();
2526 0 : for (PRUint32 i = 0; i < info.mIntegerCount; i++) {
2527 0 : if (aName == *info.mIntegerInfo[i].mName) {
2528 0 : return info.mIntegers[i].ToSMILAttr(this);
2529 : }
2530 : }
2531 : }
2532 :
2533 : // Integer Pairs:
2534 : {
2535 0 : IntegerPairAttributesInfo info = GetIntegerPairInfo();
2536 0 : for (PRUint32 i = 0; i < info.mIntegerPairCount; i++) {
2537 0 : if (aName == *info.mIntegerPairInfo[i].mName) {
2538 0 : return info.mIntegerPairs[i].ToSMILAttr(this);
2539 : }
2540 : }
2541 : }
2542 :
2543 : // Enumerations:
2544 : {
2545 0 : EnumAttributesInfo info = GetEnumInfo();
2546 0 : for (PRUint32 i = 0; i < info.mEnumCount; i++) {
2547 0 : if (aName == *info.mEnumInfo[i].mName) {
2548 0 : return info.mEnums[i].ToSMILAttr(this);
2549 : }
2550 : }
2551 : }
2552 :
2553 : // Booleans:
2554 : {
2555 0 : BooleanAttributesInfo info = GetBooleanInfo();
2556 0 : for (PRUint32 i = 0; i < info.mBooleanCount; i++) {
2557 0 : if (aName == *info.mBooleanInfo[i].mName) {
2558 0 : return info.mBooleans[i].ToSMILAttr(this);
2559 : }
2560 : }
2561 : }
2562 :
2563 : // Angles:
2564 : {
2565 0 : AngleAttributesInfo info = GetAngleInfo();
2566 0 : for (PRUint32 i = 0; i < info.mAngleCount; i++) {
2567 0 : if (aName == *info.mAngleInfo[i].mName) {
2568 0 : return info.mAngles[i].ToSMILAttr(this);
2569 : }
2570 : }
2571 : }
2572 :
2573 : // viewBox:
2574 0 : if (aName == nsGkAtoms::viewBox) {
2575 0 : nsSVGViewBox *viewBox = GetViewBox();
2576 0 : return viewBox ? viewBox->ToSMILAttr(this) : nsnull;
2577 : }
2578 :
2579 : // preserveAspectRatio:
2580 0 : if (aName == nsGkAtoms::preserveAspectRatio) {
2581 : SVGAnimatedPreserveAspectRatio *preserveAspectRatio =
2582 0 : GetPreserveAspectRatio();
2583 : return preserveAspectRatio ?
2584 0 : preserveAspectRatio->ToSMILAttr(this) : nsnull;
2585 : }
2586 :
2587 : // NumberLists:
2588 : {
2589 0 : NumberListAttributesInfo info = GetNumberListInfo();
2590 0 : for (PRUint32 i = 0; i < info.mNumberListCount; i++) {
2591 0 : if (aName == *info.mNumberListInfo[i].mName) {
2592 0 : NS_ABORT_IF_FALSE(i <= UCHAR_MAX, "Too many attributes");
2593 0 : return info.mNumberLists[i].ToSMILAttr(this, PRUint8(i));
2594 : }
2595 : }
2596 : }
2597 :
2598 : // LengthLists:
2599 : {
2600 0 : LengthListAttributesInfo info = GetLengthListInfo();
2601 0 : for (PRUint32 i = 0; i < info.mLengthListCount; i++) {
2602 0 : if (aName == *info.mLengthListInfo[i].mName) {
2603 0 : NS_ABORT_IF_FALSE(i <= UCHAR_MAX, "Too many attributes");
2604 : return info.mLengthLists[i].ToSMILAttr(this,
2605 : PRUint8(i),
2606 0 : info.mLengthListInfo[i].mAxis,
2607 0 : info.mLengthListInfo[i].mCouldZeroPadList);
2608 : }
2609 : }
2610 : }
2611 :
2612 : // PointLists:
2613 : {
2614 0 : if (GetPointListAttrName() == aName) {
2615 0 : SVGAnimatedPointList *pointList = GetAnimatedPointList();
2616 0 : if (pointList) {
2617 0 : return pointList->ToSMILAttr(this);
2618 : }
2619 : }
2620 : }
2621 :
2622 : // PathSegLists:
2623 : {
2624 0 : if (GetPathDataAttrName() == aName) {
2625 0 : SVGAnimatedPathSegList *segList = GetAnimPathSegList();
2626 0 : if (segList) {
2627 0 : return segList->ToSMILAttr(this);
2628 : }
2629 : }
2630 : }
2631 :
2632 : // Mapped attributes:
2633 0 : if (IsAttributeMapped(aName)) {
2634 : nsCSSProperty prop =
2635 0 : nsCSSProps::LookupProperty(nsDependentAtomString(aName));
2636 : // Check IsPropertyAnimatable to avoid attributes that...
2637 : // - map to explicitly unanimatable properties (e.g. 'direction')
2638 : // - map to unsupported attributes (e.g. 'glyph-orientation-horizontal')
2639 0 : if (nsSMILCSSProperty::IsPropertyAnimatable(prop)) {
2640 0 : return new nsSMILMappedAttribute(prop, this);
2641 : }
2642 : }
2643 : }
2644 :
2645 : // Strings
2646 : {
2647 0 : StringAttributesInfo info = GetStringInfo();
2648 0 : for (PRUint32 i = 0; i < info.mStringCount; i++) {
2649 0 : if (aNamespaceID == info.mStringInfo[i].mNamespaceID &&
2650 0 : aName == *info.mStringInfo[i].mName) {
2651 0 : return info.mStrings[i].ToSMILAttr(this);
2652 : }
2653 : }
2654 : }
2655 :
2656 0 : return nsnull;
2657 : }
2658 :
2659 : void
2660 0 : nsSVGElement::AnimationNeedsResample()
2661 : {
2662 0 : nsIDocument* doc = GetCurrentDoc();
2663 0 : if (doc && doc->HasAnimationController()) {
2664 0 : doc->GetAnimationController()->SetResampleNeeded();
2665 : }
2666 0 : }
2667 :
2668 : void
2669 0 : nsSVGElement::FlushAnimations()
2670 : {
2671 0 : nsIDocument* doc = GetCurrentDoc();
2672 0 : if (doc && doc->HasAnimationController()) {
2673 0 : doc->GetAnimationController()->FlushResampleRequests();
2674 : }
2675 0 : }
|