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