Coverage Report

Created: 2018-09-25 14:53

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