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