/src/mozilla-central/dom/svg/DOMSVGPointList.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 "nsSVGElement.h" |
8 | | #include "DOMSVGPointList.h" |
9 | | #include "DOMSVGPoint.h" |
10 | | #include "nsError.h" |
11 | | #include "SVGAnimatedPointList.h" |
12 | | #include "nsCOMPtr.h" |
13 | | #include "nsSVGAttrTearoffTable.h" |
14 | | #include "nsContentUtils.h" |
15 | | #include "mozilla/dom/SVGPointListBinding.h" |
16 | | #include <algorithm> |
17 | | |
18 | | // See the comment in this file's header. |
19 | | |
20 | | // local helper functions |
21 | | namespace { |
22 | | |
23 | | void |
24 | | UpdateListIndicesFromIndex(FallibleTArray<mozilla::nsISVGPoint*>& aItemsArray, |
25 | | uint32_t aStartingIndex) |
26 | 0 | { |
27 | 0 | uint32_t length = aItemsArray.Length(); |
28 | 0 |
|
29 | 0 | for (uint32_t i = aStartingIndex; i < length; ++i) { |
30 | 0 | if (aItemsArray[i]) { |
31 | 0 | aItemsArray[i]->UpdateListIndex(i); |
32 | 0 | } |
33 | 0 | } |
34 | 0 | } |
35 | | |
36 | | } // namespace |
37 | | |
38 | | namespace mozilla { |
39 | | |
40 | | static inline |
41 | | nsSVGAttrTearoffTable<void, DOMSVGPointList>& |
42 | | SVGPointListTearoffTable() |
43 | 0 | { |
44 | 0 | static nsSVGAttrTearoffTable<void, DOMSVGPointList> |
45 | 0 | sSVGPointListTearoffTable; |
46 | 0 | return sSVGPointListTearoffTable; |
47 | 0 | } |
48 | | |
49 | | NS_IMPL_CYCLE_COLLECTION_CLASS(DOMSVGPointList) |
50 | | |
51 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMSVGPointList) |
52 | 0 | // No unlinking of mElement, we'd need to null out the value pointer (the |
53 | 0 | // object it points to is held by the element) and null-check it everywhere. |
54 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER |
55 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_END |
56 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMSVGPointList) |
57 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mElement) |
58 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END |
59 | 0 | NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMSVGPointList) |
60 | 0 | NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER |
61 | 0 | NS_IMPL_CYCLE_COLLECTION_TRACE_END |
62 | | |
63 | | NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMSVGPointList) |
64 | | NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMSVGPointList) |
65 | | |
66 | 0 | NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGPointList) |
67 | 0 | NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY |
68 | 0 | NS_INTERFACE_MAP_ENTRY(nsISupports) |
69 | 0 | NS_INTERFACE_MAP_END |
70 | | |
71 | | //---------------------------------------------------------------------- |
72 | | // Helper class: AutoChangePointListNotifier |
73 | | // Stack-based helper class to pair calls to WillChangePointList and |
74 | | // DidChangePointList. |
75 | | class MOZ_RAII AutoChangePointListNotifier |
76 | | { |
77 | | public: |
78 | | explicit AutoChangePointListNotifier(DOMSVGPointList* aPointList MOZ_GUARD_OBJECT_NOTIFIER_PARAM) |
79 | | : mPointList(aPointList) |
80 | 0 | { |
81 | 0 | MOZ_GUARD_OBJECT_NOTIFIER_INIT; |
82 | 0 | MOZ_ASSERT(mPointList, "Expecting non-null pointList"); |
83 | 0 | mEmptyOrOldValue = |
84 | 0 | mPointList->Element()->WillChangePointList(); |
85 | 0 | } |
86 | | |
87 | | ~AutoChangePointListNotifier() |
88 | 0 | { |
89 | 0 | mPointList->Element()->DidChangePointList(mEmptyOrOldValue); |
90 | 0 | if (mPointList->AttrIsAnimating()) { |
91 | 0 | mPointList->Element()->AnimationNeedsResample(); |
92 | 0 | } |
93 | 0 | } |
94 | | |
95 | | private: |
96 | | DOMSVGPointList* const mPointList; |
97 | | nsAttrValue mEmptyOrOldValue; |
98 | | MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER |
99 | | }; |
100 | | |
101 | | |
102 | | /* static */ already_AddRefed<DOMSVGPointList> |
103 | | DOMSVGPointList::GetDOMWrapper(void *aList, |
104 | | nsSVGElement *aElement, |
105 | | bool aIsAnimValList) |
106 | 0 | { |
107 | 0 | RefPtr<DOMSVGPointList> wrapper = |
108 | 0 | SVGPointListTearoffTable().GetTearoff(aList); |
109 | 0 | if (!wrapper) { |
110 | 0 | wrapper = new DOMSVGPointList(aElement, aIsAnimValList); |
111 | 0 | SVGPointListTearoffTable().AddTearoff(aList, wrapper); |
112 | 0 | } |
113 | 0 | return wrapper.forget(); |
114 | 0 | } |
115 | | |
116 | | /* static */ DOMSVGPointList* |
117 | | DOMSVGPointList::GetDOMWrapperIfExists(void *aList) |
118 | 0 | { |
119 | 0 | return SVGPointListTearoffTable().GetTearoff(aList); |
120 | 0 | } |
121 | | |
122 | | DOMSVGPointList::~DOMSVGPointList() |
123 | 0 | { |
124 | 0 | // There are now no longer any references to us held by script or list items. |
125 | 0 | // Note we must use GetAnimValKey/GetBaseValKey here, NOT InternalList()! |
126 | 0 | void *key = mIsAnimValList ? |
127 | 0 | InternalAList().GetAnimValKey() : |
128 | 0 | InternalAList().GetBaseValKey(); |
129 | 0 | SVGPointListTearoffTable().RemoveTearoff(key); |
130 | 0 | } |
131 | | |
132 | | JSObject* |
133 | | DOMSVGPointList::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto) |
134 | 0 | { |
135 | 0 | return mozilla::dom::SVGPointList_Binding::Wrap(cx, this, aGivenProto); |
136 | 0 | } |
137 | | |
138 | | void |
139 | | DOMSVGPointList::InternalListWillChangeTo(const SVGPointList& aNewValue) |
140 | 0 | { |
141 | 0 | // When the number of items in our internal counterpart changes, we MUST stay |
142 | 0 | // in sync. Everything in the scary comment in |
143 | 0 | // DOMSVGLengthList::InternalBaseValListWillChangeTo applies here too! |
144 | 0 |
|
145 | 0 | uint32_t oldLength = mItems.Length(); |
146 | 0 |
|
147 | 0 | uint32_t newLength = aNewValue.Length(); |
148 | 0 | if (newLength > nsISVGPoint::MaxListIndex()) { |
149 | 0 | // It's safe to get out of sync with our internal list as long as we have |
150 | 0 | // FEWER items than it does. |
151 | 0 | newLength = nsISVGPoint::MaxListIndex(); |
152 | 0 | } |
153 | 0 |
|
154 | 0 | RefPtr<DOMSVGPointList> kungFuDeathGrip; |
155 | 0 | if (newLength < oldLength) { |
156 | 0 | // RemovingFromList() might clear last reference to |this|. |
157 | 0 | // Retain a temporary reference to keep from dying before returning. |
158 | 0 | kungFuDeathGrip = this; |
159 | 0 | } |
160 | 0 |
|
161 | 0 | // If our length will decrease, notify the items that will be removed: |
162 | 0 | for (uint32_t i = newLength; i < oldLength; ++i) { |
163 | 0 | if (mItems[i]) { |
164 | 0 | mItems[i]->RemovingFromList(); |
165 | 0 | } |
166 | 0 | } |
167 | 0 |
|
168 | 0 | if (!mItems.SetLength(newLength, fallible)) { |
169 | 0 | // We silently ignore SetLength OOM failure since being out of sync is safe |
170 | 0 | // so long as we have *fewer* items than our internal list. |
171 | 0 | mItems.Clear(); |
172 | 0 | return; |
173 | 0 | } |
174 | 0 | |
175 | 0 | // If our length has increased, null out the new pointers: |
176 | 0 | for (uint32_t i = oldLength; i < newLength; ++i) { |
177 | 0 | mItems[i] = nullptr; |
178 | 0 | } |
179 | 0 | } |
180 | | |
181 | | bool |
182 | | DOMSVGPointList::AttrIsAnimating() const |
183 | 0 | { |
184 | 0 | return InternalAList().IsAnimating(); |
185 | 0 | } |
186 | | |
187 | | bool |
188 | | DOMSVGPointList::AnimListMirrorsBaseList() const |
189 | 0 | { |
190 | 0 | return GetDOMWrapperIfExists(InternalAList().GetAnimValKey()) && |
191 | 0 | !AttrIsAnimating(); |
192 | 0 | } |
193 | | |
194 | | SVGPointList& |
195 | | DOMSVGPointList::InternalList() const |
196 | 0 | { |
197 | 0 | SVGAnimatedPointList *alist = mElement->GetAnimatedPointList(); |
198 | 0 | return mIsAnimValList && alist->IsAnimating() ? *alist->mAnimVal : alist->mBaseVal; |
199 | 0 | } |
200 | | |
201 | | SVGAnimatedPointList& |
202 | | DOMSVGPointList::InternalAList() const |
203 | 0 | { |
204 | 0 | MOZ_ASSERT(mElement->GetAnimatedPointList(), "Internal error"); |
205 | 0 | return *mElement->GetAnimatedPointList(); |
206 | 0 | } |
207 | | |
208 | | // ---------------------------------------------------------------------------- |
209 | | // nsIDOMSVGPointList implementation: |
210 | | |
211 | | void |
212 | | DOMSVGPointList::Clear(ErrorResult& aError) |
213 | 0 | { |
214 | 0 | if (IsAnimValList()) { |
215 | 0 | aError.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR); |
216 | 0 | return; |
217 | 0 | } |
218 | 0 | |
219 | 0 | if (LengthNoFlush() > 0) { |
220 | 0 | AutoChangePointListNotifier notifier(this); |
221 | 0 | // DOM list items that are to be removed must be removed before we change |
222 | 0 | // the internal list, otherwise they wouldn't be able to copy their |
223 | 0 | // internal counterparts' values! |
224 | 0 |
|
225 | 0 | InternalListWillChangeTo(SVGPointList()); // clears mItems |
226 | 0 |
|
227 | 0 | if (!AttrIsAnimating()) { |
228 | 0 | // The anim val list is in sync with the base val list |
229 | 0 | DOMSVGPointList *animList = |
230 | 0 | GetDOMWrapperIfExists(InternalAList().GetAnimValKey()); |
231 | 0 | if (animList) { |
232 | 0 | animList->InternalListWillChangeTo(SVGPointList()); // clears its mItems |
233 | 0 | } |
234 | 0 | } |
235 | 0 |
|
236 | 0 | InternalList().Clear(); |
237 | 0 | } |
238 | 0 | } |
239 | | |
240 | | already_AddRefed<nsISVGPoint> |
241 | | DOMSVGPointList::Initialize(nsISVGPoint& aNewItem, ErrorResult& aError) |
242 | 0 | { |
243 | 0 | if (IsAnimValList()) { |
244 | 0 | aError.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR); |
245 | 0 | return nullptr; |
246 | 0 | } |
247 | 0 | |
248 | 0 | // If aNewItem is already in a list we should insert a clone of aNewItem, |
249 | 0 | // and for consistency, this should happen even if *this* is the list that |
250 | 0 | // aNewItem is currently in. Note that in the case of aNewItem being in this |
251 | 0 | // list, the Clear() call before the InsertItemBefore() call would remove it |
252 | 0 | // from this list, and so the InsertItemBefore() call would not insert a |
253 | 0 | // clone of aNewItem, it would actually insert aNewItem. To prevent that |
254 | 0 | // from happening we have to do the clone here, if necessary. |
255 | 0 | |
256 | 0 | nsCOMPtr<nsISVGPoint> domItem = &aNewItem; |
257 | 0 | if (domItem->HasOwner() || domItem->IsReadonly() || |
258 | 0 | domItem->IsTranslatePoint()) { |
259 | 0 | domItem = domItem->Copy(); // must do this before changing anything! |
260 | 0 | } |
261 | 0 |
|
262 | 0 | ErrorResult rv; |
263 | 0 | Clear(rv); |
264 | 0 | MOZ_ASSERT(!rv.Failed()); |
265 | 0 | return InsertItemBefore(*domItem, 0, aError); |
266 | 0 | } |
267 | | |
268 | | already_AddRefed<nsISVGPoint> |
269 | | DOMSVGPointList::GetItem(uint32_t index, ErrorResult& error) |
270 | 0 | { |
271 | 0 | bool found; |
272 | 0 | RefPtr<nsISVGPoint> item = IndexedGetter(index, found, error); |
273 | 0 | if (!found) { |
274 | 0 | error.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); |
275 | 0 | } |
276 | 0 | return item.forget(); |
277 | 0 | } |
278 | | |
279 | | already_AddRefed<nsISVGPoint> |
280 | | DOMSVGPointList::IndexedGetter(uint32_t aIndex, bool& aFound, |
281 | | ErrorResult& aError) |
282 | 0 | { |
283 | 0 | if (IsAnimValList()) { |
284 | 0 | Element()->FlushAnimations(); |
285 | 0 | } |
286 | 0 | aFound = aIndex < LengthNoFlush(); |
287 | 0 | if (aFound) { |
288 | 0 | return GetItemAt(aIndex); |
289 | 0 | } |
290 | 0 | return nullptr; |
291 | 0 | } |
292 | | |
293 | | already_AddRefed<nsISVGPoint> |
294 | | DOMSVGPointList::InsertItemBefore(nsISVGPoint& aNewItem, uint32_t aIndex, |
295 | | ErrorResult& aError) |
296 | 0 | { |
297 | 0 | if (IsAnimValList()) { |
298 | 0 | aError.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR); |
299 | 0 | return nullptr; |
300 | 0 | } |
301 | 0 | |
302 | 0 | aIndex = std::min(aIndex, LengthNoFlush()); |
303 | 0 | if (aIndex >= nsISVGPoint::MaxListIndex()) { |
304 | 0 | aError.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); |
305 | 0 | return nullptr; |
306 | 0 | } |
307 | 0 | |
308 | 0 | nsCOMPtr<nsISVGPoint> domItem = &aNewItem; |
309 | 0 | if (domItem->HasOwner() || domItem->IsReadonly() || |
310 | 0 | domItem->IsTranslatePoint()) { |
311 | 0 | domItem = domItem->Copy(); // must do this before changing anything! |
312 | 0 | } |
313 | 0 |
|
314 | 0 | // Ensure we have enough memory so we can avoid complex error handling below: |
315 | 0 | if (!mItems.SetCapacity(mItems.Length() + 1, fallible) || |
316 | 0 | !InternalList().SetCapacity(InternalList().Length() + 1)) { |
317 | 0 | aError.Throw(NS_ERROR_OUT_OF_MEMORY); |
318 | 0 | return nullptr; |
319 | 0 | } |
320 | 0 | if (AnimListMirrorsBaseList()) { |
321 | 0 | DOMSVGPointList *animVal = |
322 | 0 | GetDOMWrapperIfExists(InternalAList().GetAnimValKey()); |
323 | 0 | MOZ_ASSERT(animVal, "animVal must be a valid pointer"); |
324 | 0 | if (!animVal->mItems.SetCapacity( |
325 | 0 | animVal->mItems.Length() + 1, fallible)) { |
326 | 0 | aError.Throw(NS_ERROR_OUT_OF_MEMORY); |
327 | 0 | return nullptr; |
328 | 0 | } |
329 | 0 | } |
330 | 0 | |
331 | 0 | AutoChangePointListNotifier notifier(this); |
332 | 0 | // Now that we know we're inserting, keep animVal list in sync as necessary. |
333 | 0 | MaybeInsertNullInAnimValListAt(aIndex); |
334 | 0 |
|
335 | 0 | InternalList().InsertItem(aIndex, domItem->ToSVGPoint()); |
336 | 0 | MOZ_ALWAYS_TRUE(mItems.InsertElementAt(aIndex, domItem, fallible)); |
337 | 0 |
|
338 | 0 | // This MUST come after the insertion into InternalList(), or else under the |
339 | 0 | // insertion into InternalList() the values read from domItem would be bad |
340 | 0 | // data from InternalList() itself!: |
341 | 0 | domItem->InsertingIntoList(this, aIndex, IsAnimValList()); |
342 | 0 |
|
343 | 0 | UpdateListIndicesFromIndex(mItems, aIndex + 1); |
344 | 0 |
|
345 | 0 | return domItem.forget(); |
346 | 0 | } |
347 | | |
348 | | already_AddRefed<nsISVGPoint> |
349 | | DOMSVGPointList::ReplaceItem(nsISVGPoint& aNewItem, uint32_t aIndex, |
350 | | ErrorResult& aError) |
351 | 0 | { |
352 | 0 | if (IsAnimValList()) { |
353 | 0 | aError.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR); |
354 | 0 | return nullptr; |
355 | 0 | } |
356 | 0 | |
357 | 0 | if (aIndex >= LengthNoFlush()) { |
358 | 0 | aError.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); |
359 | 0 | return nullptr; |
360 | 0 | } |
361 | 0 | |
362 | 0 | nsCOMPtr<nsISVGPoint> domItem = &aNewItem; |
363 | 0 | if (domItem->HasOwner() || domItem->IsReadonly() || |
364 | 0 | domItem->IsTranslatePoint()) { |
365 | 0 | domItem = domItem->Copy(); // must do this before changing anything! |
366 | 0 | } |
367 | 0 |
|
368 | 0 | AutoChangePointListNotifier notifier(this); |
369 | 0 | if (mItems[aIndex]) { |
370 | 0 | // Notify any existing DOM item of removal *before* modifying the lists so |
371 | 0 | // that the DOM item can copy the *old* value at its index: |
372 | 0 | mItems[aIndex]->RemovingFromList(); |
373 | 0 | } |
374 | 0 |
|
375 | 0 | InternalList()[aIndex] = domItem->ToSVGPoint(); |
376 | 0 | mItems[aIndex] = domItem; |
377 | 0 |
|
378 | 0 | // This MUST come after the ToSVGPoint() call, otherwise that call |
379 | 0 | // would end up reading bad data from InternalList()! |
380 | 0 | domItem->InsertingIntoList(this, aIndex, IsAnimValList()); |
381 | 0 |
|
382 | 0 | return domItem.forget(); |
383 | 0 | } |
384 | | |
385 | | already_AddRefed<nsISVGPoint> |
386 | | DOMSVGPointList::RemoveItem(uint32_t aIndex, ErrorResult& aError) |
387 | 0 | { |
388 | 0 | if (IsAnimValList()) { |
389 | 0 | aError.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR); |
390 | 0 | return nullptr; |
391 | 0 | } |
392 | 0 | |
393 | 0 | if (aIndex >= LengthNoFlush()) { |
394 | 0 | aError.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); |
395 | 0 | return nullptr; |
396 | 0 | } |
397 | 0 | |
398 | 0 | AutoChangePointListNotifier notifier(this); |
399 | 0 | // Now that we know we're removing, keep animVal list in sync as necessary. |
400 | 0 | // Do this *before* touching InternalList() so the removed item can get its |
401 | 0 | // internal value. |
402 | 0 | MaybeRemoveItemFromAnimValListAt(aIndex); |
403 | 0 |
|
404 | 0 | // We have to return the removed item, so get it, creating it if necessary: |
405 | 0 | RefPtr<nsISVGPoint> result = GetItemAt(aIndex); |
406 | 0 |
|
407 | 0 | // Notify the DOM item of removal *before* modifying the lists so that the |
408 | 0 | // DOM item can copy its *old* value: |
409 | 0 | mItems[aIndex]->RemovingFromList(); |
410 | 0 |
|
411 | 0 | InternalList().RemoveItem(aIndex); |
412 | 0 | mItems.RemoveElementAt(aIndex); |
413 | 0 |
|
414 | 0 | UpdateListIndicesFromIndex(mItems, aIndex); |
415 | 0 |
|
416 | 0 | return result.forget(); |
417 | 0 | } |
418 | | |
419 | | already_AddRefed<nsISVGPoint> |
420 | | DOMSVGPointList::GetItemAt(uint32_t aIndex) |
421 | 0 | { |
422 | 0 | MOZ_ASSERT(aIndex < mItems.Length()); |
423 | 0 |
|
424 | 0 | if (!mItems[aIndex]) { |
425 | 0 | mItems[aIndex] = new DOMSVGPoint(this, aIndex, IsAnimValList()); |
426 | 0 | } |
427 | 0 | RefPtr<nsISVGPoint> result = mItems[aIndex]; |
428 | 0 | return result.forget(); |
429 | 0 | } |
430 | | |
431 | | void |
432 | | DOMSVGPointList::MaybeInsertNullInAnimValListAt(uint32_t aIndex) |
433 | 0 | { |
434 | 0 | MOZ_ASSERT(!IsAnimValList(), "call from baseVal to animVal"); |
435 | 0 |
|
436 | 0 | if (!AnimListMirrorsBaseList()) { |
437 | 0 | return; |
438 | 0 | } |
439 | 0 | |
440 | 0 | // The anim val list is in sync with the base val list |
441 | 0 | DOMSVGPointList *animVal = |
442 | 0 | GetDOMWrapperIfExists(InternalAList().GetAnimValKey()); |
443 | 0 |
|
444 | 0 | MOZ_ASSERT(animVal, "AnimListMirrorsBaseList() promised a non-null animVal"); |
445 | 0 | MOZ_ASSERT(animVal->mItems.Length() == mItems.Length(), |
446 | 0 | "animVal list not in sync!"); |
447 | 0 | MOZ_ALWAYS_TRUE(animVal->mItems.InsertElementAt(aIndex, nullptr, fallible)); |
448 | 0 |
|
449 | 0 | UpdateListIndicesFromIndex(animVal->mItems, aIndex + 1); |
450 | 0 | } |
451 | | |
452 | | void |
453 | | DOMSVGPointList::MaybeRemoveItemFromAnimValListAt(uint32_t aIndex) |
454 | 0 | { |
455 | 0 | MOZ_ASSERT(!IsAnimValList(), "call from baseVal to animVal"); |
456 | 0 |
|
457 | 0 | if (!AnimListMirrorsBaseList()) { |
458 | 0 | return; |
459 | 0 | } |
460 | 0 | |
461 | 0 | // This needs to be a strong reference; otherwise, the RemovingFromList call |
462 | 0 | // below might drop the last reference to animVal before we're done with it. |
463 | 0 | RefPtr<DOMSVGPointList> animVal = |
464 | 0 | GetDOMWrapperIfExists(InternalAList().GetAnimValKey()); |
465 | 0 |
|
466 | 0 | MOZ_ASSERT(animVal, "AnimListMirrorsBaseList() promised a non-null animVal"); |
467 | 0 | MOZ_ASSERT(animVal->mItems.Length() == mItems.Length(), |
468 | 0 | "animVal list not in sync!"); |
469 | 0 |
|
470 | 0 | if (animVal->mItems[aIndex]) { |
471 | 0 | animVal->mItems[aIndex]->RemovingFromList(); |
472 | 0 | } |
473 | 0 | animVal->mItems.RemoveElementAt(aIndex); |
474 | 0 |
|
475 | 0 | UpdateListIndicesFromIndex(animVal->mItems, aIndex); |
476 | 0 | } |
477 | | |
478 | | } // namespace mozilla |