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