Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/svg/SVGAnimatedPathSegList.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 "SVGAnimatedPathSegList.h"
8
9
#include "DOMSVGPathSegList.h"
10
#include "mozilla/Move.h"
11
#include "nsSVGElement.h"
12
#include "nsSVGAttrTearoffTable.h"
13
#include "nsSMILValue.h"
14
#include "SVGPathSegListSMILType.h"
15
16
// See the comments in this file's header!
17
18
namespace mozilla {
19
20
nsresult
21
SVGAnimatedPathSegList::SetBaseValueString(const nsAString& aValue)
22
0
{
23
0
  SVGPathData newBaseValue;
24
0
25
0
  // The spec says that the path data is parsed and accepted up to the first
26
0
  // error encountered, so we don't return early if an error occurs. However,
27
0
  // we do want to throw any error code from setAttribute if there's a problem.
28
0
29
0
  nsresult rv = newBaseValue.SetValueFromString(aValue);
30
0
31
0
  // We must send these notifications *before* changing mBaseVal! Our baseVal's
32
0
  // DOM wrapper list may have to remove DOM items from itself, and any removed
33
0
  // DOM items need to copy their internal counterpart's values *before* we
34
0
  // change them. See the comments in
35
0
  // DOMSVGPathSegList::InternalListWillChangeTo().
36
0
37
0
  DOMSVGPathSegList *baseValWrapper =
38
0
    DOMSVGPathSegList::GetDOMWrapperIfExists(GetBaseValKey());
39
0
  if (baseValWrapper) {
40
0
    baseValWrapper->InternalListWillChangeTo(newBaseValue);
41
0
  }
42
0
43
0
  DOMSVGPathSegList* animValWrapper = nullptr;
44
0
  if (!IsAnimating()) {  // DOM anim val wraps our base val too!
45
0
    animValWrapper = DOMSVGPathSegList::GetDOMWrapperIfExists(GetAnimValKey());
46
0
    if (animValWrapper) {
47
0
      animValWrapper->InternalListWillChangeTo(newBaseValue);
48
0
    }
49
0
  }
50
0
51
0
  // Only now may we modify mBaseVal!
52
0
53
0
  // We don't need to call DidChange* here - we're only called by
54
0
  // nsSVGElement::ParseAttribute under Element::SetAttr,
55
0
  // which takes care of notifying.
56
0
57
0
  nsresult rv2 = mBaseVal.CopyFrom(newBaseValue);
58
0
  if (NS_FAILED(rv2)) {
59
0
    // Attempting to increase mBaseVal's length failed (mBaseVal is left
60
0
    // unmodified). We MUST keep any DOM wrappers in sync:
61
0
    if (baseValWrapper) {
62
0
      baseValWrapper->InternalListWillChangeTo(mBaseVal);
63
0
    }
64
0
    if (animValWrapper) {
65
0
      animValWrapper->InternalListWillChangeTo(mBaseVal);
66
0
    }
67
0
    return rv2;
68
0
  }
69
0
  return rv;
70
0
}
71
72
void
73
SVGAnimatedPathSegList::ClearBaseValue()
74
0
{
75
0
  // We must send these notifications *before* changing mBaseVal! (See above.)
76
0
77
0
  DOMSVGPathSegList *baseValWrapper =
78
0
    DOMSVGPathSegList::GetDOMWrapperIfExists(GetBaseValKey());
79
0
  if (baseValWrapper) {
80
0
    baseValWrapper->InternalListWillChangeTo(SVGPathData());
81
0
  }
82
0
83
0
  if (!IsAnimating()) { // DOM anim val wraps our base val too!
84
0
    DOMSVGPathSegList *animValWrapper =
85
0
      DOMSVGPathSegList::GetDOMWrapperIfExists(GetAnimValKey());
86
0
    if (animValWrapper) {
87
0
      animValWrapper->InternalListWillChangeTo(SVGPathData());
88
0
    }
89
0
  }
90
0
91
0
  mBaseVal.Clear();
92
0
  // Caller notifies
93
0
}
94
95
nsresult
96
SVGAnimatedPathSegList::SetAnimValue(const SVGPathData& aNewAnimValue,
97
                                     nsSVGElement *aElement)
98
0
{
99
0
  // Note that a new animation may totally change the number of items in the
100
0
  // animVal list, either replacing what was essentially a mirror of the
101
0
  // baseVal list, or else replacing and overriding an existing animation.
102
0
  // Unfortunately it is not possible for us to reliably distinguish between
103
0
  // calls to this method that are setting a new sample for an existing
104
0
  // animation, and calls that are setting the first sample of an animation
105
0
  // that will override an existing animation. In the case of DOMSVGPathSegList
106
0
  // the InternalListWillChangeTo method is not virtually free as it is for the
107
0
  // other DOM list classes, so this is a shame. We'd quite like to be able to
108
0
  // skip the call if possible.
109
0
110
0
  // We must send these notifications *before* changing mAnimVal! (See above.)
111
0
112
0
  DOMSVGPathSegList *domWrapper =
113
0
    DOMSVGPathSegList::GetDOMWrapperIfExists(GetAnimValKey());
114
0
  if (domWrapper) {
115
0
    domWrapper->InternalListWillChangeTo(aNewAnimValue);
116
0
  }
117
0
  if (!mAnimVal) {
118
0
    mAnimVal = new SVGPathData();
119
0
  }
120
0
  nsresult rv = mAnimVal->CopyFrom(aNewAnimValue);
121
0
  if (NS_FAILED(rv)) {
122
0
    // OOM. We clear the animation and, importantly, ClearAnimValue() ensures
123
0
    // that mAnimVal's DOM wrapper (if any) is kept in sync!
124
0
    ClearAnimValue(aElement);
125
0
  }
126
0
  aElement->DidAnimatePathSegList();
127
0
  return rv;
128
0
}
129
130
void
131
SVGAnimatedPathSegList::ClearAnimValue(nsSVGElement *aElement)
132
0
{
133
0
  // We must send these notifications *before* changing mAnimVal! (See above.)
134
0
135
0
  DOMSVGPathSegList *domWrapper =
136
0
    DOMSVGPathSegList::GetDOMWrapperIfExists(GetAnimValKey());
137
0
  if (domWrapper) {
138
0
    // When all animation ends, animVal simply mirrors baseVal, which may have
139
0
    // a different number of items to the last active animated value.
140
0
    //
141
0
    domWrapper->InternalListWillChangeTo(mBaseVal);
142
0
  }
143
0
  mAnimVal = nullptr;
144
0
  aElement->DidAnimatePathSegList();
145
0
}
146
147
bool
148
SVGAnimatedPathSegList::IsRendered() const
149
0
{
150
0
  return mAnimVal ? !mAnimVal->IsEmpty() : !mBaseVal.IsEmpty();
151
0
}
152
153
UniquePtr<nsISMILAttr>
154
SVGAnimatedPathSegList::ToSMILAttr(nsSVGElement *aElement)
155
0
{
156
0
  return MakeUnique<SMILAnimatedPathSegList>(this, aElement);
157
0
}
158
159
nsresult
160
SVGAnimatedPathSegList::
161
  SMILAnimatedPathSegList::ValueFromString(const nsAString& aStr,
162
                               const dom::SVGAnimationElement* /*aSrcElement*/,
163
                               nsSMILValue& aValue,
164
                               bool& aPreventCachingOfSandwich) const
165
0
{
166
0
  nsSMILValue val(SVGPathSegListSMILType::Singleton());
167
0
  SVGPathDataAndInfo *list = static_cast<SVGPathDataAndInfo*>(val.mU.mPtr);
168
0
  nsresult rv = list->SetValueFromString(aStr);
169
0
  if (NS_SUCCEEDED(rv)) {
170
0
    list->SetElement(mElement);
171
0
    aValue = std::move(val);
172
0
  }
173
0
  aPreventCachingOfSandwich = false;
174
0
  return rv;
175
0
}
176
177
nsSMILValue
178
SVGAnimatedPathSegList::SMILAnimatedPathSegList::GetBaseValue() const
179
0
{
180
0
  // To benefit from Return Value Optimization and avoid copy constructor calls
181
0
  // due to our use of return-by-value, we must return the exact same object
182
0
  // from ALL return points. This function must only return THIS variable:
183
0
  nsSMILValue val;
184
0
185
0
  nsSMILValue tmp(SVGPathSegListSMILType::Singleton());
186
0
  SVGPathDataAndInfo *list = static_cast<SVGPathDataAndInfo*>(tmp.mU.mPtr);
187
0
  nsresult rv = list->CopyFrom(mVal->mBaseVal);
188
0
  if (NS_SUCCEEDED(rv)) {
189
0
    list->SetElement(mElement);
190
0
    val = std::move(tmp);
191
0
  }
192
0
  return val;
193
0
}
194
195
nsresult
196
SVGAnimatedPathSegList::SMILAnimatedPathSegList::SetAnimValue(const nsSMILValue& aValue)
197
0
{
198
0
  NS_ASSERTION(aValue.mType == SVGPathSegListSMILType::Singleton(),
199
0
               "Unexpected type to assign animated value");
200
0
  if (aValue.mType == SVGPathSegListSMILType::Singleton()) {
201
0
    mVal->SetAnimValue(*static_cast<SVGPathDataAndInfo*>(aValue.mU.mPtr),
202
0
                       mElement);
203
0
  }
204
0
  return NS_OK;
205
0
}
206
207
void
208
SVGAnimatedPathSegList::SMILAnimatedPathSegList::ClearAnimValue()
209
0
{
210
0
  if (mVal->mAnimVal) {
211
0
    mVal->ClearAnimValue(mElement);
212
0
  }
213
0
}
214
215
size_t
216
SVGAnimatedPathSegList::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
217
0
{
218
0
  size_t total = mBaseVal.SizeOfExcludingThis(aMallocSizeOf);
219
0
  if (mAnimVal) {
220
0
    mAnimVal->SizeOfIncludingThis(aMallocSizeOf);
221
0
  }
222
0
  return total;
223
0
}
224
225
} // namespace mozilla