LCOV - code coverage report
Current view: top level - dom/svg - DOMSVGPathSegList.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 5 242 2.1 %
Date: 2017-07-14 16:53:18 Functions: 2 30 6.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "nsSVGElement.h"
       8             : #include "DOMSVGPathSegList.h"
       9             : #include "DOMSVGPathSeg.h"
      10             : #include "nsError.h"
      11             : #include "SVGAnimatedPathSegList.h"
      12             : #include "nsCOMPtr.h"
      13             : #include "nsSVGAttrTearoffTable.h"
      14             : #include "SVGPathSegUtils.h"
      15             : #include "mozilla/dom/SVGPathSegListBinding.h"
      16             : 
      17             : // See the comment in this file's header.
      18             : 
      19             : namespace mozilla {
      20             : 
      21             :   static inline
      22             : nsSVGAttrTearoffTable<void, DOMSVGPathSegList>&
      23          88 : SVGPathSegListTearoffTable()
      24             : {
      25             :   static nsSVGAttrTearoffTable<void, DOMSVGPathSegList>
      26          88 :     sSVGPathSegListTearoffTable;
      27          88 :   return sSVGPathSegListTearoffTable;
      28             : }
      29             : 
      30             : NS_IMPL_CYCLE_COLLECTION_CLASS(DOMSVGPathSegList)
      31             : 
      32           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMSVGPathSegList)
      33             :   // No unlinking of mElement, we'd need to null out the value pointer (the
      34             :   // object it points to is held by the element) and null-check it everywhere.
      35           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
      36           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
      37           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMSVGPathSegList)
      38           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mElement)
      39           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
      40           0 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMSVGPathSegList)
      41           0 :   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
      42           0 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
      43             : 
      44           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMSVGPathSegList)
      45           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMSVGPathSegList)
      46             : 
      47           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGPathSegList)
      48           0 :   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
      49           0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
      50           0 : NS_INTERFACE_MAP_END
      51             : 
      52             : 
      53             : //----------------------------------------------------------------------
      54             : // Helper class: AutoChangePathSegListNotifier
      55             : // Stack-based helper class to pair calls to WillChangePathSegList and
      56             : // DidChangePathSegList.
      57             : class MOZ_RAII AutoChangePathSegListNotifier
      58             : {
      59             : public:
      60           0 :   explicit AutoChangePathSegListNotifier(DOMSVGPathSegList* aPathSegList MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
      61           0 :     : mPathSegList(aPathSegList)
      62             :   {
      63           0 :     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
      64           0 :     MOZ_ASSERT(mPathSegList, "Expecting non-null pathSegList");
      65             :     mEmptyOrOldValue =
      66           0 :       mPathSegList->Element()->WillChangePathSegList();
      67           0 :   }
      68             : 
      69           0 :   ~AutoChangePathSegListNotifier()
      70           0 :   {
      71           0 :     mPathSegList->Element()->DidChangePathSegList(mEmptyOrOldValue);
      72           0 :     if (mPathSegList->AttrIsAnimating()) {
      73           0 :       mPathSegList->Element()->AnimationNeedsResample();
      74             :     }
      75           0 :   }
      76             : 
      77             : private:
      78             :   DOMSVGPathSegList* const mPathSegList;
      79             :   nsAttrValue        mEmptyOrOldValue;
      80             :   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
      81             : };
      82             : 
      83             : /* static */ already_AddRefed<DOMSVGPathSegList>
      84           0 : DOMSVGPathSegList::GetDOMWrapper(void *aList,
      85             :                                  nsSVGElement *aElement,
      86             :                                  bool aIsAnimValList)
      87             : {
      88             :   RefPtr<DOMSVGPathSegList> wrapper =
      89           0 :     SVGPathSegListTearoffTable().GetTearoff(aList);
      90           0 :   if (!wrapper) {
      91           0 :     wrapper = new DOMSVGPathSegList(aElement, aIsAnimValList);
      92           0 :     SVGPathSegListTearoffTable().AddTearoff(aList, wrapper);
      93             :   }
      94           0 :   return wrapper.forget();
      95             : }
      96             : 
      97             : /* static */ DOMSVGPathSegList*
      98          88 : DOMSVGPathSegList::GetDOMWrapperIfExists(void *aList)
      99             : {
     100          88 :   return SVGPathSegListTearoffTable().GetTearoff(aList);
     101             : }
     102             : 
     103           0 : DOMSVGPathSegList::~DOMSVGPathSegList()
     104             : {
     105             :   // There are now no longer any references to us held by script or list items.
     106             :   // Note we must use GetAnimValKey/GetBaseValKey here, NOT InternalList()!
     107           0 :   void *key = mIsAnimValList ?
     108           0 :     InternalAList().GetAnimValKey() :
     109           0 :     InternalAList().GetBaseValKey();
     110           0 :   SVGPathSegListTearoffTable().RemoveTearoff(key);
     111           0 : }
     112             : 
     113             : JSObject*
     114           0 : DOMSVGPathSegList::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
     115             : {
     116           0 :   return mozilla::dom::SVGPathSegListBinding::Wrap(cx, this, aGivenProto);
     117             : }
     118             : 
     119             : void
     120           0 : DOMSVGPathSegList::InternalListWillChangeTo(const SVGPathData& aNewValue)
     121             : {
     122             :   // When the number of items in our internal counterpart changes, we MUST stay
     123             :   // in sync. Everything in the scary comment in
     124             :   // DOMSVGLengthList::InternalBaseValListWillChangeTo applies here just as
     125             :   // much, but we have the additional issue that failing to stay in sync would
     126             :   // mean that - assuming we aren't reading bad memory - we would likely end up
     127             :   // decoding command types from argument floats when looking in our
     128             :   // SVGPathData's data array! Either way, we'll likely then go down
     129             :   // NS_NOTREACHED code paths, or end up reading/setting more bad memory!!
     130             : 
     131             :   // The only time that our other DOM list type implementations remove items is
     132             :   // if those items become surplus items due to an attribute change or SMIL
     133             :   // animation sample shortening the list. In general though, they try to keep
     134             :   // their existing DOM items, even when things change. To be consistent, we'd
     135             :   // really like to do the same thing. However, because different types of path
     136             :   // segment correspond to different DOMSVGPathSeg subclasses, the type of
     137             :   // items in our list are generally not the same, which makes this harder for
     138             :   // us. We have to remove DOM segments if their type is not the same as the
     139             :   // type of the new internal segment at their index.
     140             :   //
     141             :   // We also need to sync up mInternalDataIndex, but since we need to loop over
     142             :   // all the items in the new list checking types anyway, that's almost
     143             :   // insignificant in terms of overhead.
     144             :   //
     145             :   // Note that this method is called on every single SMIL animation resample
     146             :   // and we have no way to short circuit the overhead since we don't have a
     147             :   // way to tell if the call is due to a new animation, or a resample of an
     148             :   // existing animation (when the number and type of items would be the same).
     149             :   // (Note that a new animation could start overriding an existing animation at
     150             :   // any time, so checking IsAnimating() wouldn't work.) Because we get called
     151             :   // on every sample, it would not be acceptable alternative to throw away all
     152             :   // our items and let them be recreated lazily, since that would break what
     153             :   // script sees!
     154             : 
     155           0 :   uint32_t length = mItems.Length();
     156           0 :   uint32_t index = 0;
     157             : 
     158           0 :   uint32_t dataLength = aNewValue.mData.Length();
     159           0 :   uint32_t dataIndex = 0; // index into aNewValue's raw data array
     160             : 
     161             :   uint32_t newSegType;
     162             : 
     163           0 :   RefPtr<DOMSVGPathSegList> kungFuDeathGrip;
     164           0 :   if (length) {
     165             :     // RemovingFromList() might clear last reference to |this|.
     166             :     // Retain a temporary reference to keep from dying before returning.
     167             :     //
     168             :     // NOTE: For path-seg lists (unlike other list types), we have to do this
     169             :     // *whenever our list is nonempty* (even if we're growing in length).
     170             :     // That's because the path-seg-type of any segment could differ between old
     171             :     // list vs. new list, which will make us destroy & recreate that segment,
     172             :     // which could remove the last reference to us.
     173             :     //
     174             :     // (We explicitly *don't* want to create a kungFuDeathGrip in the length=0
     175             :     // case, though, because we do hit this code inside our constructor before
     176             :     // any other owning references have been added, and at that point, the
     177             :     // deathgrip-removal would make us die before we exit our constructor.)
     178           0 :     kungFuDeathGrip = this;
     179             :   }
     180             : 
     181           0 :   while (index < length && dataIndex < dataLength) {
     182           0 :     newSegType = SVGPathSegUtils::DecodeType(aNewValue.mData[dataIndex]);
     183           0 :     if (ItemAt(index) && ItemAt(index)->Type() != newSegType) {
     184           0 :       ItemAt(index)->RemovingFromList();
     185           0 :       ItemAt(index) = nullptr;
     186             :     }
     187             :     // Only after the RemovingFromList() can we touch mInternalDataIndex!
     188           0 :     mItems[index].mInternalDataIndex = dataIndex;
     189           0 :     ++index;
     190           0 :     dataIndex += 1 + SVGPathSegUtils::ArgCountForType(newSegType);
     191             :   }
     192             : 
     193           0 :   MOZ_ASSERT((index == length && dataIndex <= dataLength) ||
     194             :              (index <= length && dataIndex == dataLength),
     195             :              "very bad - list corruption?");
     196             : 
     197           0 :   if (index < length) {
     198             :     // aNewValue has fewer items than our previous internal counterpart
     199             : 
     200           0 :     uint32_t newLength = index;
     201             : 
     202             :     // Remove excess items from the list:
     203           0 :     for (; index < length; ++index) {
     204           0 :       if (ItemAt(index)) {
     205           0 :         ItemAt(index)->RemovingFromList();
     206           0 :         ItemAt(index) = nullptr;
     207             :       }
     208             :     }
     209             : 
     210             :     // Only now may we truncate mItems
     211           0 :     mItems.TruncateLength(newLength);
     212           0 :   } else if (dataIndex < dataLength) {
     213             :     // aNewValue has more items than our previous internal counterpart
     214             : 
     215             :     // Sync mItems:
     216           0 :     while (dataIndex < dataLength) {
     217           0 :       if (mItems.Length() &&
     218           0 :           mItems.Length() - 1 > DOMSVGPathSeg::MaxListIndex()) {
     219             :         // It's safe to get out of sync with our internal list as long as we
     220             :         // have FEWER items than it does.
     221           0 :         return;
     222             :       }
     223           0 :       if (!mItems.AppendElement(ItemProxy(nullptr, dataIndex), fallible)) {
     224             :         // OOM
     225           0 :         ErrorResult rv;
     226           0 :         Clear(rv);
     227           0 :         MOZ_ASSERT(!rv.Failed());
     228           0 :         return;
     229             :       }
     230           0 :       dataIndex += 1 + SVGPathSegUtils::ArgCountForType(SVGPathSegUtils::DecodeType(aNewValue.mData[dataIndex]));
     231             :     }
     232             :   }
     233             : 
     234           0 :   MOZ_ASSERT(dataIndex == dataLength, "Serious processing error");
     235           0 :   MOZ_ASSERT(index == length, "Serious counting error");
     236             : }
     237             : 
     238             : bool
     239           0 : DOMSVGPathSegList::AttrIsAnimating() const
     240             : {
     241           0 :   return InternalAList().IsAnimating();
     242             : }
     243             : 
     244             : bool
     245           0 : DOMSVGPathSegList::AnimListMirrorsBaseList() const
     246             : {
     247           0 :   return GetDOMWrapperIfExists(InternalAList().GetAnimValKey()) &&
     248           0 :            !AttrIsAnimating();
     249             : }
     250             : 
     251             : SVGPathData&
     252           0 : DOMSVGPathSegList::InternalList() const
     253             : {
     254           0 :   SVGAnimatedPathSegList *alist = mElement->GetAnimPathSegList();
     255           0 :   return mIsAnimValList && alist->IsAnimating() ? *alist->mAnimVal : alist->mBaseVal;
     256             : }
     257             : 
     258             : SVGAnimatedPathSegList&
     259           0 : DOMSVGPathSegList::InternalAList() const
     260             : {
     261           0 :   MOZ_ASSERT(mElement->GetAnimPathSegList(), "Internal error");
     262           0 :   return *mElement->GetAnimPathSegList();
     263             : }
     264             : 
     265             : // ----------------------------------------------------------------------------
     266             : // nsIDOMSVGPathSegList implementation:
     267             : 
     268             : void
     269           0 : DOMSVGPathSegList::Clear(ErrorResult& aError)
     270             : {
     271           0 :   if (IsAnimValList()) {
     272           0 :     aError.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
     273           0 :     return;
     274             :   }
     275             : 
     276           0 :   if (LengthNoFlush() > 0) {
     277           0 :     AutoChangePathSegListNotifier notifier(this);
     278             :     // DOM list items that are to be removed must be removed before we change
     279             :     // the internal list, otherwise they wouldn't be able to copy their
     280             :     // internal counterparts' values!
     281             : 
     282           0 :     InternalListWillChangeTo(SVGPathData()); // clears mItems
     283             : 
     284           0 :     if (!AttrIsAnimating()) {
     285             :       // The anim val list is in sync with the base val list
     286             :       DOMSVGPathSegList *animList =
     287           0 :         GetDOMWrapperIfExists(InternalAList().GetAnimValKey());
     288           0 :       if (animList) {
     289           0 :         animList->InternalListWillChangeTo(SVGPathData()); // clears its mItems
     290             :       }
     291             :     }
     292             : 
     293           0 :     InternalList().Clear();
     294             :   }
     295             : }
     296             : 
     297             : already_AddRefed<DOMSVGPathSeg>
     298           0 : DOMSVGPathSegList::Initialize(DOMSVGPathSeg& aNewItem, ErrorResult& aError)
     299             : {
     300           0 :   if (IsAnimValList()) {
     301           0 :     aError.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
     302           0 :     return nullptr;
     303             :   }
     304             : 
     305             :   // If aNewItem is already in a list we should insert a clone of aNewItem,
     306             :   // and for consistency, this should happen even if *this* is the list that
     307             :   // aNewItem is currently in. Note that in the case of aNewItem being in this
     308             :   // list, the Clear() call before the InsertItemBefore() call would remove it
     309             :   // from this list, and so the InsertItemBefore() call would not insert a
     310             :   // clone of aNewItem, it would actually insert aNewItem. To prevent that
     311             :   // from happening we have to do the clone here, if necessary.
     312             : 
     313           0 :   RefPtr<DOMSVGPathSeg> domItem = &aNewItem;
     314           0 :   if (aNewItem.HasOwner()) {
     315           0 :     domItem = aNewItem.Clone();
     316             :   }
     317             : 
     318           0 :   Clear(aError);
     319           0 :   MOZ_ASSERT(!aError.Failed(), "How could this fail?");
     320           0 :   return InsertItemBefore(*domItem, 0, aError);
     321             : }
     322             : 
     323             : already_AddRefed<DOMSVGPathSeg>
     324           0 : DOMSVGPathSegList::GetItem(uint32_t index, ErrorResult& error)
     325             : {
     326             :   bool found;
     327           0 :   RefPtr<DOMSVGPathSeg> item = IndexedGetter(index, found, error);
     328           0 :   if (!found) {
     329           0 :     error.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     330             :   }
     331           0 :   return item.forget();
     332             : }
     333             : 
     334             : already_AddRefed<DOMSVGPathSeg>
     335           0 : DOMSVGPathSegList::IndexedGetter(uint32_t aIndex, bool& aFound,
     336             :                                  ErrorResult& aError)
     337             : {
     338           0 :   if (IsAnimValList()) {
     339           0 :     Element()->FlushAnimations();
     340             :   }
     341           0 :   aFound = aIndex < LengthNoFlush();
     342           0 :   if (aFound) {
     343           0 :     return GetItemAt(aIndex);
     344             :   }
     345           0 :   return nullptr;
     346             : }
     347             : 
     348             : already_AddRefed<DOMSVGPathSeg>
     349           0 : DOMSVGPathSegList::InsertItemBefore(DOMSVGPathSeg& aNewItem,
     350             :                                     uint32_t aIndex,
     351             :                                     ErrorResult& aError)
     352             : {
     353           0 :   if (IsAnimValList()) {
     354           0 :     aError.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
     355           0 :     return nullptr;
     356             :   }
     357             : 
     358             :   uint32_t internalIndex;
     359           0 :   if (aIndex < LengthNoFlush()) {
     360           0 :     internalIndex = mItems[aIndex].mInternalDataIndex;
     361             :   } else {
     362           0 :     aIndex = LengthNoFlush();
     363           0 :     internalIndex = InternalList().mData.Length();
     364             :   }
     365           0 :   if (aIndex >= DOMSVGPathSeg::MaxListIndex()) {
     366           0 :     aError.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     367           0 :     return nullptr;
     368             :   }
     369             : 
     370           0 :   RefPtr<DOMSVGPathSeg> domItem = &aNewItem;
     371           0 :   if (domItem->HasOwner()) {
     372           0 :     domItem = domItem->Clone(); // must do this before changing anything!
     373             :   }
     374             : 
     375           0 :   uint32_t argCount = SVGPathSegUtils::ArgCountForType(domItem->Type());
     376             : 
     377             :   // Ensure we have enough memory so we can avoid complex error handling below:
     378           0 :   if (!mItems.SetCapacity(mItems.Length() + 1, fallible) ||
     379           0 :       !InternalList().mData.SetCapacity(InternalList().mData.Length() + 1 + argCount,
     380             :                                         fallible)) {
     381           0 :     aError.Throw(NS_ERROR_OUT_OF_MEMORY);
     382           0 :     return nullptr;
     383             :   }
     384           0 :   if (AnimListMirrorsBaseList()) {
     385             :     DOMSVGPathSegList *animVal =
     386           0 :       GetDOMWrapperIfExists(InternalAList().GetAnimValKey());
     387           0 :     MOZ_ASSERT(animVal, "animVal should be a valid pointer");
     388           0 :     if (!animVal->mItems.SetCapacity(
     389           0 :           animVal->mItems.Length() + 1, fallible)) {
     390           0 :       aError.Throw(NS_ERROR_OUT_OF_MEMORY);
     391           0 :       return nullptr;
     392             :     }
     393             :   }
     394             : 
     395           0 :   AutoChangePathSegListNotifier notifier(this);
     396             :   // Now that we know we're inserting, keep animVal list in sync as necessary.
     397           0 :   MaybeInsertNullInAnimValListAt(aIndex, internalIndex, argCount);
     398             : 
     399             :   float segAsRaw[1 + NS_SVG_PATH_SEG_MAX_ARGS];
     400           0 :   domItem->ToSVGPathSegEncodedData(segAsRaw);
     401             : 
     402           0 :   MOZ_ALWAYS_TRUE(InternalList().mData.InsertElementsAt(internalIndex,
     403             :                                                         segAsRaw,
     404             :                                                         1 + argCount,
     405             :                                                         fallible));
     406           0 :   MOZ_ALWAYS_TRUE(mItems.InsertElementAt(aIndex,
     407             :                                          ItemProxy(domItem.get(),
     408             :                                                    internalIndex),
     409             :                                          fallible));
     410             : 
     411             :   // This MUST come after the insertion into InternalList(), or else under the
     412             :   // insertion into InternalList() the values read from domItem would be bad
     413             :   // data from InternalList() itself!:
     414           0 :   domItem->InsertingIntoList(this, aIndex, IsAnimValList());
     415             : 
     416           0 :   UpdateListIndicesFromIndex(aIndex + 1, argCount + 1);
     417             : 
     418           0 :   return domItem.forget();
     419             : }
     420             : 
     421             : already_AddRefed<DOMSVGPathSeg>
     422           0 : DOMSVGPathSegList::ReplaceItem(DOMSVGPathSeg& aNewItem,
     423             :                                uint32_t aIndex,
     424             :                                ErrorResult& aError)
     425             : {
     426           0 :   if (IsAnimValList()) {
     427           0 :     aError.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
     428           0 :     return nullptr;
     429             :   }
     430             : 
     431           0 :   if (aIndex >= LengthNoFlush()) {
     432           0 :     aError.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     433           0 :     return nullptr;
     434             :   }
     435             : 
     436           0 :   RefPtr<DOMSVGPathSeg> domItem = &aNewItem;
     437           0 :   if (domItem->HasOwner()) {
     438           0 :     domItem = domItem->Clone(); // must do this before changing anything!
     439             :   }
     440             : 
     441           0 :   AutoChangePathSegListNotifier notifier(this);
     442           0 :   if (ItemAt(aIndex)) {
     443             :     // Notify any existing DOM item of removal *before* modifying the lists so
     444             :     // that the DOM item can copy the *old* value at its index:
     445           0 :     ItemAt(aIndex)->RemovingFromList();
     446             :   }
     447             : 
     448           0 :   uint32_t internalIndex = mItems[aIndex].mInternalDataIndex;
     449             :   // We use InternalList() to get oldArgCount since we may not have a DOM
     450             :   // wrapper at the index being replaced.
     451           0 :   uint32_t oldType = SVGPathSegUtils::DecodeType(InternalList().mData[internalIndex]);
     452             : 
     453             :   // NOTE: ArgCountForType returns a (small) unsigned value, but we're
     454             :   // intentionally putting it in a signed variable, because we're going to
     455             :   // subtract these values and might produce something negative.
     456           0 :   int32_t oldArgCount = SVGPathSegUtils::ArgCountForType(oldType);
     457           0 :   int32_t newArgCount = SVGPathSegUtils::ArgCountForType(domItem->Type());
     458             : 
     459             :   float segAsRaw[1 + NS_SVG_PATH_SEG_MAX_ARGS];
     460           0 :   domItem->ToSVGPathSegEncodedData(segAsRaw);
     461             : 
     462           0 :   if (!InternalList().mData.ReplaceElementsAt(internalIndex, 1 + oldArgCount,
     463           0 :                                               segAsRaw, 1 + newArgCount,
     464             :                                               fallible)) {
     465           0 :     aError.Throw(NS_ERROR_OUT_OF_MEMORY);
     466           0 :     return nullptr;
     467             :   }
     468           0 :   ItemAt(aIndex) = domItem;
     469             : 
     470             :   // This MUST come after the ToSVGPathSegEncodedData call, otherwise that call
     471             :   // would end up reading bad data from InternalList()!
     472           0 :   domItem->InsertingIntoList(this, aIndex, IsAnimValList());
     473             : 
     474           0 :   int32_t delta = newArgCount - oldArgCount;
     475           0 :   if (delta != 0) {
     476           0 :     for (uint32_t i = aIndex + 1; i < LengthNoFlush(); ++i) {
     477           0 :       mItems[i].mInternalDataIndex += delta;
     478             :     }
     479             :   }
     480             : 
     481           0 :   return domItem.forget();
     482             : }
     483             : 
     484             : already_AddRefed<DOMSVGPathSeg>
     485           0 : DOMSVGPathSegList::RemoveItem(uint32_t aIndex,
     486             :                               ErrorResult& aError)
     487             : {
     488           0 :   if (IsAnimValList()) {
     489           0 :     aError.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
     490           0 :     return nullptr;
     491             :   }
     492             : 
     493           0 :   if (aIndex >= LengthNoFlush()) {
     494           0 :     aError.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     495           0 :     return nullptr;
     496             :   }
     497             :   // We have to return the removed item, so get it, creating it if necessary:
     498           0 :   RefPtr<DOMSVGPathSeg> result = GetItemAt(aIndex);
     499             : 
     500           0 :   AutoChangePathSegListNotifier notifier(this);
     501             :   // Notify the DOM item of removal *before* modifying the lists so that the
     502             :   // DOM item can copy its *old* value:
     503           0 :   ItemAt(aIndex)->RemovingFromList();
     504             : 
     505           0 :   uint32_t internalIndex = mItems[aIndex].mInternalDataIndex;
     506           0 :   uint32_t segType = SVGPathSegUtils::DecodeType(InternalList().mData[internalIndex]);
     507             :   // NOTE: ArgCountForType returns a (small) unsigned value, but we're
     508             :   // intentionally putting it in a signed value, because we're going to
     509             :   // negate it, and you can't negate an unsigned value.
     510           0 :   int32_t argCount = SVGPathSegUtils::ArgCountForType(segType);
     511             : 
     512             :   // Now that we know we're removing, keep animVal list in sync as necessary.
     513             :   // Do this *before* touching InternalList() so the removed item can get its
     514             :   // internal value.
     515           0 :   MaybeRemoveItemFromAnimValListAt(aIndex, argCount);
     516             : 
     517           0 :   InternalList().mData.RemoveElementsAt(internalIndex, 1 + argCount);
     518           0 :   mItems.RemoveElementAt(aIndex);
     519             : 
     520           0 :   UpdateListIndicesFromIndex(aIndex, -(argCount + 1));
     521             : 
     522           0 :   return result.forget();
     523             : }
     524             : 
     525             : already_AddRefed<DOMSVGPathSeg>
     526           0 : DOMSVGPathSegList::GetItemAt(uint32_t aIndex)
     527             : {
     528           0 :   MOZ_ASSERT(aIndex < mItems.Length());
     529             : 
     530           0 :   if (!ItemAt(aIndex)) {
     531           0 :     ItemAt(aIndex) = DOMSVGPathSeg::CreateFor(this, aIndex, IsAnimValList());
     532             :   }
     533           0 :   RefPtr<DOMSVGPathSeg> result = ItemAt(aIndex);
     534           0 :   return result.forget();
     535             : }
     536             : 
     537             : void
     538           0 : DOMSVGPathSegList::
     539             :   MaybeInsertNullInAnimValListAt(uint32_t aIndex,
     540             :                                  uint32_t aInternalIndex,
     541             :                                  uint32_t aArgCountForItem)
     542             : {
     543           0 :   MOZ_ASSERT(!IsAnimValList(), "call from baseVal to animVal");
     544             : 
     545           0 :   if (!AnimListMirrorsBaseList()) {
     546           0 :     return;
     547             :   }
     548             : 
     549             :   // The anim val list is in sync with the base val list
     550             :   DOMSVGPathSegList *animVal =
     551           0 :     GetDOMWrapperIfExists(InternalAList().GetAnimValKey());
     552             : 
     553           0 :   MOZ_ASSERT(animVal, "AnimListMirrorsBaseList() promised a non-null animVal");
     554           0 :   MOZ_ASSERT(animVal->mItems.Length() == mItems.Length(),
     555             :              "animVal list not in sync!");
     556           0 :   MOZ_ALWAYS_TRUE(animVal->mItems.InsertElementAt(aIndex,
     557             :                                                   ItemProxy(nullptr,
     558             :                                                             aInternalIndex),
     559             :                                                   fallible));
     560             : 
     561           0 :   animVal->UpdateListIndicesFromIndex(aIndex + 1, 1 + aArgCountForItem);
     562             : }
     563             : 
     564             : void
     565           0 : DOMSVGPathSegList::
     566             :   MaybeRemoveItemFromAnimValListAt(uint32_t aIndex,
     567             :                                    int32_t aArgCountForItem)
     568             : {
     569           0 :   MOZ_ASSERT(!IsAnimValList(), "call from baseVal to animVal");
     570             : 
     571           0 :   if (!AnimListMirrorsBaseList()) {
     572           0 :     return;
     573             :   }
     574             : 
     575             :   // This needs to be a strong reference; otherwise, the RemovingFromList call
     576             :   // below might drop the last reference to animVal before we're done with it.
     577             :   RefPtr<DOMSVGPathSegList> animVal =
     578           0 :     GetDOMWrapperIfExists(InternalAList().GetAnimValKey());
     579             : 
     580           0 :   MOZ_ASSERT(animVal, "AnimListMirrorsBaseList() promised a non-null animVal");
     581           0 :   MOZ_ASSERT(animVal->mItems.Length() == mItems.Length(),
     582             :              "animVal list not in sync!");
     583             : 
     584           0 :   if (animVal->ItemAt(aIndex)) {
     585           0 :     animVal->ItemAt(aIndex)->RemovingFromList();
     586             :   }
     587           0 :   animVal->mItems.RemoveElementAt(aIndex);
     588             : 
     589           0 :   animVal->UpdateListIndicesFromIndex(aIndex, -(1 + aArgCountForItem));
     590             : }
     591             : 
     592             : void
     593           0 : DOMSVGPathSegList::UpdateListIndicesFromIndex(uint32_t aStartingIndex,
     594             :                                               int32_t  aInternalDataIndexDelta)
     595             : {
     596           0 :   uint32_t length = mItems.Length();
     597             : 
     598           0 :   for (uint32_t i = aStartingIndex; i < length; ++i) {
     599           0 :     mItems[i].mInternalDataIndex += aInternalDataIndexDelta;
     600           0 :     if (ItemAt(i)) {
     601           0 :       ItemAt(i)->UpdateListIndex(i);
     602             :     }
     603             :   }
     604           0 : }
     605             : 
     606             : } // namespace mozilla

Generated by: LCOV version 1.13