Bug 632143 patch 1: Update animVal after modifying baseVal length, for DOMSVGLengthList and DOMSVGNumberList. r=roc a=blocking-final+
authorJonathan Watt <jwatt@jwatt.org>
Tue, 15 Feb 2011 23:54:26 -0800
changeset 62657 78f8b9ee9ea854d04388907b069117dc771b7b49
parent 62656 58cb9a41c8b41c6c7364c87ea4300915e22c7e6a
child 62658 2cf3e2ce18080c15a63cd88a39835ee794167ccf
push idunknown
push userunknown
push dateunknown
reviewersroc, blocking-final
bugs632143
milestone2.0b12pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 632143 patch 1: Update animVal after modifying baseVal length, for DOMSVGLengthList and DOMSVGNumberList. r=roc a=blocking-final+
content/svg/content/src/DOMSVGLengthList.cpp
content/svg/content/src/DOMSVGLengthList.h
content/svg/content/src/DOMSVGNumberList.cpp
content/svg/content/src/DOMSVGNumberList.h
--- a/content/svg/content/src/DOMSVGLengthList.cpp
+++ b/content/svg/content/src/DOMSVGLengthList.cpp
@@ -150,17 +150,17 @@ DOMSVGLengthList::Clear()
 {
   if (IsAnimValList()) {
     return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
   }
 
   if (Length() > 0) {
     // Notify any existing DOM items of removal *before* truncating the lists
     // so that they can find their SVGLength internal counterparts and copy
-    // their values:
+    // their values. This also notifies the animVal list:
     mAList->InternalBaseValListWillChangeTo(SVGLengthList());
 
     mItems.Clear();
     InternalList().Clear();
     Element()->DidChangeLengthList(AttrEnum(), PR_TRUE);
 #ifdef MOZ_SMIL
     if (mAList->IsAnimating()) {
       Element()->AnimationNeedsResample();
@@ -241,16 +241,19 @@ DOMSVGLengthList::InsertItemBefore(nsIDO
   }
 
   // Ensure we have enough memory so we can avoid complex error handling below:
   if (!mItems.SetCapacity(mItems.Length() + 1) ||
       !InternalList().SetCapacity(InternalList().Length() + 1)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
+  // Now that we know we're inserting, keep animVal list in sync as necessary.
+  MaybeInsertNullInAnimValListAt(index);
+
   InternalList().InsertItem(index, domItem->ToSVGLength());
   mItems.InsertElementAt(index, domItem.get());
 
   // This MUST come after the insertion into InternalList(), or else under the
   // insertion into InternalList() the values read from domItem would be bad
   // data from InternalList() itself!:
   domItem->InsertingIntoList(this, AttrEnum(), index, IsAnimValList());
 
@@ -317,16 +320,22 @@ DOMSVGLengthList::RemoveItem(PRUint32 in
   *_retval = nsnull;
   if (IsAnimValList()) {
     return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
   }
 
   if (index >= Length()) {
     return NS_ERROR_DOM_INDEX_SIZE_ERR;
   }
+
+  // Now that we know we're removing, keep animVal list in sync as necessary.
+  // Do this *before* touching InternalList() so the removed item can get its
+  // internal value.
+  MaybeRemoveItemFromAnimValListAt(index);
+
   // We have to return the removed item, so make sure it exists:
   EnsureItemAt(index);
 
   // Notify the DOM item of removal *before* modifying the lists so that the
   // DOM item can copy its *old* value:
   mItems[index]->RemovingFromList();
   NS_ADDREF(*_retval = mItems[index]);
 
@@ -354,9 +363,52 @@ DOMSVGLengthList::AppendItem(nsIDOMSVGLe
 void
 DOMSVGLengthList::EnsureItemAt(PRUint32 aIndex)
 {
   if (!mItems[aIndex]) {
     mItems[aIndex] = new DOMSVGLength(this, AttrEnum(), aIndex, IsAnimValList());
   }
 }
 
+void
+DOMSVGLengthList::MaybeInsertNullInAnimValListAt(PRUint32 aIndex)
+{
+  NS_ABORT_IF_FALSE(!IsAnimValList(), "call from baseVal to animVal");
+
+  DOMSVGLengthList* animVal = mAList->mAnimVal;
+
+  if (!animVal || mAList->IsAnimating()) {
+    // No animVal list wrapper, or animVal not a clone of baseVal
+    return;
+  }
+
+  NS_ABORT_IF_FALSE(animVal->mItems.Length() == mItems.Length(),
+                    "animVal list not in sync!");
+
+  animVal->mItems.InsertElementAt(aIndex, static_cast<DOMSVGLength*>(nsnull));
+
+  UpdateListIndicesFromIndex(animVal->mItems, aIndex + 1);
+}
+
+void
+DOMSVGLengthList::MaybeRemoveItemFromAnimValListAt(PRUint32 aIndex)
+{
+  NS_ABORT_IF_FALSE(!IsAnimValList(), "call from baseVal to animVal");
+
+  DOMSVGLengthList* animVal = mAList->mAnimVal;
+
+  if (!animVal || mAList->IsAnimating()) {
+    // No animVal list wrapper, or animVal not a clone of baseVal
+    return;
+  }
+
+  NS_ABORT_IF_FALSE(animVal->mItems.Length() == mItems.Length(),
+                    "animVal list not in sync!");
+
+  if (animVal->mItems[aIndex]) {
+    animVal->mItems[aIndex]->RemovingFromList();
+  }
+  animVal->mItems.RemoveElementAt(aIndex);
+
+  UpdateListIndicesFromIndex(animVal->mItems, aIndex);
+}
+
 } // namespace mozilla
--- a/content/svg/content/src/DOMSVGLengthList.h
+++ b/content/svg/content/src/DOMSVGLengthList.h
@@ -141,16 +141,19 @@ private:
    * get const protection, but our setter methods guard against changing
    * animVal lists.
    */
   SVGLengthList& InternalList();
 
   /// Creates a DOMSVGLength for aIndex, if it doesn't already exist.
   void EnsureItemAt(PRUint32 aIndex);
 
+  void MaybeInsertNullInAnimValListAt(PRUint32 aIndex);
+  void MaybeRemoveItemFromAnimValListAt(PRUint32 aIndex);
+
   // Weak refs to our DOMSVGLength items. The items are friends and take care
   // of clearing our pointer to them when they die.
   nsTArray<DOMSVGLength*> mItems;
 
   nsRefPtr<DOMSVGAnimatedLengthList> mAList;
 };
 
 } // namespace mozilla
--- a/content/svg/content/src/DOMSVGNumberList.cpp
+++ b/content/svg/content/src/DOMSVGNumberList.cpp
@@ -150,17 +150,17 @@ DOMSVGNumberList::Clear()
 {
   if (IsAnimValList()) {
     return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
   }
 
   if (Length() > 0) {
     // Notify any existing DOM items of removal *before* truncating the lists
     // so that they can find their SVGNumber internal counterparts and copy
-    // their values:
+    // their values. This also notifies the animVal list:
     mAList->InternalBaseValListWillChangeTo(SVGNumberList());
 
     mItems.Clear();
     InternalList().Clear();
     Element()->DidChangeNumberList(AttrEnum(), PR_TRUE);
 #ifdef MOZ_SMIL
     if (mAList->IsAnimating()) {
       Element()->AnimationNeedsResample();
@@ -241,16 +241,19 @@ DOMSVGNumberList::InsertItemBefore(nsIDO
   }
 
   // Ensure we have enough memory so we can avoid complex error handling below:
   if (!mItems.SetCapacity(mItems.Length() + 1) ||
       !InternalList().SetCapacity(InternalList().Length() + 1)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
+  // Now that we know we're inserting, keep animVal list in sync as necessary.
+  MaybeInsertNullInAnimValListAt(index);
+
   InternalList().InsertItem(index, domItem->ToSVGNumber());
   mItems.InsertElementAt(index, domItem.get());
 
   // This MUST come after the insertion into InternalList(), or else under the
   // insertion into InternalList() the values read from domItem would be bad
   // data from InternalList() itself!:
   domItem->InsertingIntoList(this, AttrEnum(), index, IsAnimValList());
 
@@ -317,16 +320,22 @@ DOMSVGNumberList::RemoveItem(PRUint32 in
   *_retval = nsnull;
   if (IsAnimValList()) {
     return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
   }
 
   if (index >= Length()) {
     return NS_ERROR_DOM_INDEX_SIZE_ERR;
   }
+
+  // Now that we know we're removing, keep animVal list in sync as necessary.
+  // Do this *before* touching InternalList() so the removed item can get its
+  // internal value.
+  MaybeRemoveItemFromAnimValListAt(index);
+
   // We have to return the removed item, so make sure it exists:
   EnsureItemAt(index);
 
   // Notify the DOM item of removal *before* modifying the lists so that the
   // DOM item can copy its *old* value:
   mItems[index]->RemovingFromList();
   NS_ADDREF(*_retval = mItems[index]);
 
@@ -354,9 +363,52 @@ DOMSVGNumberList::AppendItem(nsIDOMSVGNu
 void
 DOMSVGNumberList::EnsureItemAt(PRUint32 aIndex)
 {
   if (!mItems[aIndex]) {
     mItems[aIndex] = new DOMSVGNumber(this, AttrEnum(), aIndex, IsAnimValList());
   }
 }
 
+void
+DOMSVGNumberList::MaybeInsertNullInAnimValListAt(PRUint32 aIndex)
+{
+  NS_ABORT_IF_FALSE(!IsAnimValList(), "call from baseVal to animVal");
+
+  DOMSVGNumberList* animVal = mAList->mAnimVal;
+
+  if (!animVal || mAList->IsAnimating()) {
+    // No animVal list wrapper, or animVal not a clone of baseVal
+    return;
+  }
+
+  NS_ABORT_IF_FALSE(animVal->mItems.Length() == mItems.Length(),
+                    "animVal list not in sync!");
+
+  animVal->mItems.InsertElementAt(aIndex, static_cast<DOMSVGNumber*>(nsnull));
+
+  UpdateListIndicesFromIndex(animVal->mItems, aIndex + 1);
+}
+
+void
+DOMSVGNumberList::MaybeRemoveItemFromAnimValListAt(PRUint32 aIndex)
+{
+  NS_ABORT_IF_FALSE(!IsAnimValList(), "call from baseVal to animVal");
+
+  DOMSVGNumberList* animVal = mAList->mAnimVal;
+
+  if (!animVal || mAList->IsAnimating()) {
+    // No animVal list wrapper, or animVal not a clone of baseVal
+    return;
+  }
+
+  NS_ABORT_IF_FALSE(animVal->mItems.Length() == mItems.Length(),
+                    "animVal list not in sync!");
+
+  if (animVal->mItems[aIndex]) {
+    animVal->mItems[aIndex]->RemovingFromList();
+  }
+  animVal->mItems.RemoveElementAt(aIndex);
+
+  UpdateListIndicesFromIndex(animVal->mItems, aIndex);
+}
+
 } // namespace mozilla
--- a/content/svg/content/src/DOMSVGNumberList.h
+++ b/content/svg/content/src/DOMSVGNumberList.h
@@ -136,16 +136,19 @@ private:
    * get const protection, but our setter methods guard against changing
    * animVal lists.
    */
   SVGNumberList& InternalList();
 
   /// Creates a DOMSVGNumber for aIndex, if it doesn't already exist.
   void EnsureItemAt(PRUint32 aIndex);
 
+  void MaybeInsertNullInAnimValListAt(PRUint32 aIndex);
+  void MaybeRemoveItemFromAnimValListAt(PRUint32 aIndex);
+
   // Weak refs to our DOMSVGNumber items. The items are friends and take care
   // of clearing our pointer to them when they die.
   nsTArray<DOMSVGNumber*> mItems;
 
   nsRefPtr<DOMSVGAnimatedNumberList> mAList;
 };
 
 } // namespace mozilla