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