LCOV - code coverage report
Current view: top level - dom/svg - DOMSVGLengthList.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 185 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 23 0.0 %
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 "DOMSVGLengthList.h"
       9             : #include "DOMSVGLength.h"
      10             : #include "nsError.h"
      11             : #include "SVGAnimatedLengthList.h"
      12             : #include "nsCOMPtr.h"
      13             : #include "mozilla/dom/SVGLengthListBinding.h"
      14             : #include <algorithm>
      15             : 
      16             : // See the comment in this file's header.
      17             : 
      18             : // local helper functions
      19             : namespace {
      20             : 
      21             : using mozilla::DOMSVGLength;
      22             : 
      23           0 : void UpdateListIndicesFromIndex(FallibleTArray<DOMSVGLength*>& aItemsArray,
      24             :                                 uint32_t aStartingIndex)
      25             : {
      26           0 :   uint32_t length = aItemsArray.Length();
      27             : 
      28           0 :   for (uint32_t i = aStartingIndex; i < length; ++i) {
      29           0 :     if (aItemsArray[i]) {
      30           0 :       aItemsArray[i]->UpdateListIndex(i);
      31             :     }
      32             :   }
      33           0 : }
      34             : 
      35             : } // namespace
      36             : 
      37             : namespace mozilla {
      38             : 
      39             : // We could use NS_IMPL_CYCLE_COLLECTION(, except that in Unlink() we need to
      40             : // clear our DOMSVGAnimatedLengthList's weak ref to us to be safe. (The other
      41             : // option would be to not unlink and rely on the breaking of the other edges in
      42             : // the cycle, as NS_SVG_VAL_IMPL_CYCLE_COLLECTION does.)
      43             : NS_IMPL_CYCLE_COLLECTION_CLASS(DOMSVGLengthList)
      44             : 
      45           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMSVGLengthList)
      46           0 :   if (tmp->mAList) {
      47           0 :     if (tmp->IsAnimValList()) {
      48           0 :       tmp->mAList->mAnimVal = nullptr;
      49             :     } else {
      50           0 :       tmp->mAList->mBaseVal = nullptr;
      51             :     }
      52           0 :     NS_IMPL_CYCLE_COLLECTION_UNLINK(mAList)
      53             :   }
      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(DOMSVGLengthList)
      57           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAList)
      58           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
      59           0 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMSVGLengthList)
      60           0 :   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
      61           0 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
      62             : 
      63           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMSVGLengthList)
      64           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMSVGLengthList)
      65             : 
      66           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGLengthList)
      67           0 :   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
      68           0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
      69           0 : NS_INTERFACE_MAP_END
      70             : 
      71             : JSObject*
      72           0 : DOMSVGLengthList::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
      73             : {
      74           0 :   return mozilla::dom::SVGLengthListBinding::Wrap(cx, this, aGivenProto);
      75             : }
      76             : 
      77             : //----------------------------------------------------------------------
      78             : // Helper class: AutoChangeLengthListNotifier
      79             : // Stack-based helper class to pair calls to WillChangeLengthList and
      80             : // DidChangeLengthList.
      81             : class MOZ_RAII AutoChangeLengthListNotifier
      82             : {
      83             : public:
      84           0 :   explicit AutoChangeLengthListNotifier(DOMSVGLengthList* aLengthList MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
      85           0 :     : mLengthList(aLengthList)
      86             :   {
      87           0 :     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
      88           0 :     MOZ_ASSERT(mLengthList, "Expecting non-null lengthList");
      89             :     mEmptyOrOldValue =
      90           0 :       mLengthList->Element()->WillChangeLengthList(mLengthList->AttrEnum());
      91           0 :   }
      92             : 
      93           0 :   ~AutoChangeLengthListNotifier()
      94           0 :   {
      95           0 :     mLengthList->Element()->DidChangeLengthList(mLengthList->AttrEnum(),
      96           0 :                                                 mEmptyOrOldValue);
      97           0 :     if (mLengthList->IsAnimating()) {
      98           0 :       mLengthList->Element()->AnimationNeedsResample();
      99             :     }
     100           0 :   }
     101             : 
     102             : private:
     103             :   DOMSVGLengthList* const mLengthList;
     104             :   nsAttrValue       mEmptyOrOldValue;
     105             :   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
     106             : };
     107             : 
     108             : void
     109           0 : DOMSVGLengthList::InternalListLengthWillChange(uint32_t aNewLength)
     110             : {
     111           0 :   uint32_t oldLength = mItems.Length();
     112             : 
     113           0 :   if (aNewLength > DOMSVGLength::MaxListIndex()) {
     114             :     // It's safe to get out of sync with our internal list as long as we have
     115             :     // FEWER items than it does.
     116           0 :     aNewLength = DOMSVGLength::MaxListIndex();
     117             :   }
     118             : 
     119           0 :   RefPtr<DOMSVGLengthList> kungFuDeathGrip;
     120           0 :   if (aNewLength < oldLength) {
     121             :     // RemovingFromList() might clear last reference to |this|.
     122             :     // Retain a temporary reference to keep from dying before returning.
     123           0 :     kungFuDeathGrip = this;
     124             :   }
     125             : 
     126             :   // If our length will decrease, notify the items that will be removed:
     127           0 :   for (uint32_t i = aNewLength; i < oldLength; ++i) {
     128           0 :     if (mItems[i]) {
     129           0 :       mItems[i]->RemovingFromList();
     130             :     }
     131             :   }
     132             : 
     133           0 :   if (!mItems.SetLength(aNewLength, fallible)) {
     134             :     // We silently ignore SetLength OOM failure since being out of sync is safe
     135             :     // so long as we have *fewer* items than our internal list.
     136           0 :     mItems.Clear();
     137           0 :     return;
     138             :   }
     139             : 
     140             :   // If our length has increased, null out the new pointers:
     141           0 :   for (uint32_t i = oldLength; i < aNewLength; ++i) {
     142           0 :     mItems[i] = nullptr;
     143             :   }
     144             : }
     145             : 
     146             : SVGLengthList&
     147           0 : DOMSVGLengthList::InternalList() const
     148             : {
     149           0 :   SVGAnimatedLengthList *alist = Element()->GetAnimatedLengthList(AttrEnum());
     150           0 :   return IsAnimValList() && alist->mAnimVal ? *alist->mAnimVal : alist->mBaseVal;
     151             : }
     152             : 
     153             : // ----------------------------------------------------------------------------
     154             : 
     155             : void
     156           0 : DOMSVGLengthList::Clear(ErrorResult& aError)
     157             : {
     158           0 :   if (IsAnimValList()) {
     159           0 :     aError.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
     160           0 :     return;
     161             :   }
     162             : 
     163           0 :   if (LengthNoFlush() > 0) {
     164           0 :     AutoChangeLengthListNotifier notifier(this);
     165             :     // Notify any existing DOM items of removal *before* truncating the lists
     166             :     // so that they can find their SVGLength internal counterparts and copy
     167             :     // their values. This also notifies the animVal list:
     168           0 :     mAList->InternalBaseValListWillChangeTo(SVGLengthList());
     169             : 
     170           0 :     mItems.Clear();
     171           0 :     InternalList().Clear();
     172             :   }
     173             : }
     174             : 
     175             : already_AddRefed<DOMSVGLength>
     176           0 : DOMSVGLengthList::Initialize(DOMSVGLength& newItem,
     177             :                              ErrorResult& error)
     178             : {
     179           0 :   if (IsAnimValList()) {
     180           0 :     error.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
     181           0 :     return nullptr;
     182             :   }
     183             : 
     184             :   // If newItem already has an owner or is reflecting an attribute, we should
     185             :   // insert a clone of newItem, and for consistency, this should happen even if
     186             :   // *this* is the list that newItem is currently in. Note that in the case of
     187             :   // newItem being in this list, the Clear() call before the InsertItemBefore()
     188             :   // call would remove it from this list, and so the InsertItemBefore() call
     189             :   // would not insert a clone of newItem, it would actually insert newItem. To
     190             :   // prevent that from happening we have to do the clone here, if necessary.
     191             : 
     192           0 :   RefPtr<DOMSVGLength> domItem = &newItem;
     193           0 :   if (!domItem) {
     194           0 :     error.Throw(NS_ERROR_DOM_SVG_WRONG_TYPE_ERR);
     195           0 :     return nullptr;
     196             :   }
     197           0 :   if (domItem->HasOwner() || domItem->IsReflectingAttribute()) {
     198           0 :     domItem = domItem->Copy();
     199             :   }
     200             : 
     201           0 :   ErrorResult rv;
     202           0 :   Clear(rv);
     203           0 :   MOZ_ASSERT(!rv.Failed());
     204           0 :   return InsertItemBefore(*domItem, 0, error);
     205             : }
     206             : 
     207             : already_AddRefed<DOMSVGLength>
     208           0 : DOMSVGLengthList::GetItem(uint32_t index, ErrorResult& error)
     209             : {
     210             :   bool found;
     211           0 :   RefPtr<DOMSVGLength> item = IndexedGetter(index, found, error);
     212           0 :   if (!found) {
     213           0 :     error.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     214             :   }
     215           0 :   return item.forget();
     216             : }
     217             : 
     218             : already_AddRefed<DOMSVGLength>
     219           0 : DOMSVGLengthList::IndexedGetter(uint32_t index, bool& found, ErrorResult& error)
     220             : {
     221           0 :   if (IsAnimValList()) {
     222           0 :     Element()->FlushAnimations();
     223             :   }
     224           0 :   found = index < LengthNoFlush();
     225           0 :   if (found) {
     226           0 :     return GetItemAt(index);
     227             :   }
     228           0 :   return nullptr;
     229             : }
     230             : 
     231             : already_AddRefed<DOMSVGLength>
     232           0 : DOMSVGLengthList::InsertItemBefore(DOMSVGLength& newItem,
     233             :                                    uint32_t index,
     234             :                                    ErrorResult& error)
     235             : {
     236           0 :   if (IsAnimValList()) {
     237           0 :     error.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
     238           0 :     return nullptr;
     239             :   }
     240             : 
     241           0 :   index = std::min(index, LengthNoFlush());
     242           0 :   if (index >= DOMSVGLength::MaxListIndex()) {
     243           0 :     error.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     244           0 :     return nullptr;
     245             :   }
     246             : 
     247           0 :   RefPtr<DOMSVGLength> domItem = &newItem;
     248           0 :   if (!domItem) {
     249           0 :     error.Throw(NS_ERROR_DOM_SVG_WRONG_TYPE_ERR);
     250           0 :     return nullptr;
     251             :   }
     252           0 :   if (domItem->HasOwner() || domItem->IsReflectingAttribute()) {
     253           0 :     domItem = domItem->Copy(); // must do this before changing anything!
     254             :   }
     255             : 
     256             :   // Ensure we have enough memory so we can avoid complex error handling below:
     257           0 :   if (!mItems.SetCapacity(mItems.Length() + 1, fallible) ||
     258           0 :       !InternalList().SetCapacity(InternalList().Length() + 1)) {
     259           0 :     error.Throw(NS_ERROR_OUT_OF_MEMORY);
     260           0 :     return nullptr;
     261             :   }
     262           0 :   if (AnimListMirrorsBaseList()) {
     263           0 :     if (!mAList->mAnimVal->mItems.SetCapacity(
     264           0 :           mAList->mAnimVal->mItems.Length() + 1, fallible)) {
     265           0 :       error.Throw(NS_ERROR_OUT_OF_MEMORY);
     266           0 :       return nullptr;
     267             :     }
     268             :   }
     269             : 
     270           0 :   AutoChangeLengthListNotifier notifier(this);
     271             :   // Now that we know we're inserting, keep animVal list in sync as necessary.
     272           0 :   MaybeInsertNullInAnimValListAt(index);
     273             : 
     274           0 :   InternalList().InsertItem(index, domItem->ToSVGLength());
     275           0 :   MOZ_ALWAYS_TRUE(mItems.InsertElementAt(index, domItem.get(), fallible));
     276             : 
     277             :   // This MUST come after the insertion into InternalList(), or else under the
     278             :   // insertion into InternalList() the values read from domItem would be bad
     279             :   // data from InternalList() itself!:
     280           0 :   domItem->InsertingIntoList(this, AttrEnum(), index, IsAnimValList());
     281             : 
     282           0 :   UpdateListIndicesFromIndex(mItems, index + 1);
     283             : 
     284           0 :   return domItem.forget();
     285             : }
     286             : 
     287             : already_AddRefed<DOMSVGLength>
     288           0 : DOMSVGLengthList::ReplaceItem(DOMSVGLength& newItem,
     289             :                               uint32_t index,
     290             :                               ErrorResult& error)
     291             : {
     292           0 :   if (IsAnimValList()) {
     293           0 :     error.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
     294           0 :     return nullptr;
     295             :   }
     296             : 
     297           0 :   RefPtr<DOMSVGLength> domItem = &newItem;
     298           0 :   if (!domItem) {
     299           0 :     error.Throw(NS_ERROR_DOM_SVG_WRONG_TYPE_ERR);
     300           0 :     return nullptr;
     301             :   }
     302           0 :   if (index >= LengthNoFlush()) {
     303           0 :     error.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     304           0 :     return nullptr;
     305             :   }
     306           0 :   if (domItem->HasOwner() || domItem->IsReflectingAttribute()) {
     307           0 :     domItem = domItem->Copy(); // must do this before changing anything!
     308             :   }
     309             : 
     310           0 :   AutoChangeLengthListNotifier notifier(this);
     311           0 :   if (mItems[index]) {
     312             :     // Notify any existing DOM item of removal *before* modifying the lists so
     313             :     // that the DOM item can copy the *old* value at its index:
     314           0 :     mItems[index]->RemovingFromList();
     315             :   }
     316             : 
     317           0 :   InternalList()[index] = domItem->ToSVGLength();
     318           0 :   mItems[index] = domItem;
     319             : 
     320             :   // This MUST come after the ToSVGPoint() call, otherwise that call
     321             :   // would end up reading bad data from InternalList()!
     322           0 :   domItem->InsertingIntoList(this, AttrEnum(), index, IsAnimValList());
     323             : 
     324           0 :   return domItem.forget();
     325             : }
     326             : 
     327             : already_AddRefed<DOMSVGLength>
     328           0 : DOMSVGLengthList::RemoveItem(uint32_t index,
     329             :                              ErrorResult& error)
     330             : {
     331           0 :   if (IsAnimValList()) {
     332           0 :     error.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
     333           0 :     return nullptr;
     334             :   }
     335             : 
     336           0 :   if (index >= LengthNoFlush()) {
     337           0 :     error.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     338           0 :     return nullptr;
     339             :   }
     340             : 
     341           0 :   AutoChangeLengthListNotifier notifier(this);
     342             :   // Now that we know we're removing, keep animVal list in sync as necessary.
     343             :   // Do this *before* touching InternalList() so the removed item can get its
     344             :   // internal value.
     345           0 :   MaybeRemoveItemFromAnimValListAt(index);
     346             : 
     347             :   // We have to return the removed item, so get it, creating it if necessary:
     348           0 :   nsCOMPtr<DOMSVGLength> result = GetItemAt(index);
     349             : 
     350             :   // Notify the DOM item of removal *before* modifying the lists so that the
     351             :   // DOM item can copy its *old* value:
     352           0 :   mItems[index]->RemovingFromList();
     353             : 
     354           0 :   InternalList().RemoveItem(index);
     355           0 :   mItems.RemoveElementAt(index);
     356             : 
     357           0 :   UpdateListIndicesFromIndex(mItems, index);
     358             : 
     359           0 :   return result.forget();
     360             : }
     361             : 
     362             : already_AddRefed<DOMSVGLength>
     363           0 : DOMSVGLengthList::GetItemAt(uint32_t aIndex)
     364             : {
     365           0 :   MOZ_ASSERT(aIndex < mItems.Length());
     366             : 
     367           0 :   if (!mItems[aIndex]) {
     368           0 :     mItems[aIndex] = new DOMSVGLength(this, AttrEnum(), aIndex, IsAnimValList());
     369             :   }
     370           0 :   RefPtr<DOMSVGLength> result = mItems[aIndex];
     371           0 :   return result.forget();
     372             : }
     373             : 
     374             : void
     375           0 : DOMSVGLengthList::MaybeInsertNullInAnimValListAt(uint32_t aIndex)
     376             : {
     377           0 :   MOZ_ASSERT(!IsAnimValList(), "call from baseVal to animVal");
     378             : 
     379           0 :   if (!AnimListMirrorsBaseList()) {
     380           0 :     return;
     381             :   }
     382             : 
     383           0 :   DOMSVGLengthList* animVal = mAList->mAnimVal;
     384             : 
     385           0 :   MOZ_ASSERT(animVal, "AnimListMirrorsBaseList() promised a non-null animVal");
     386           0 :   MOZ_ASSERT(animVal->mItems.Length() == mItems.Length(),
     387             :              "animVal list not in sync!");
     388           0 :   MOZ_ALWAYS_TRUE(animVal->mItems.InsertElementAt(aIndex, nullptr, fallible));
     389             : 
     390           0 :   UpdateListIndicesFromIndex(animVal->mItems, aIndex + 1);
     391             : }
     392             : 
     393             : void
     394           0 : DOMSVGLengthList::MaybeRemoveItemFromAnimValListAt(uint32_t aIndex)
     395             : {
     396           0 :   MOZ_ASSERT(!IsAnimValList(), "call from baseVal to animVal");
     397             : 
     398           0 :   if (!AnimListMirrorsBaseList()) {
     399           0 :     return;
     400             :   }
     401             : 
     402             :   // This needs to be a strong reference; otherwise, the RemovingFromList call
     403             :   // below might drop the last reference to animVal before we're done with it.
     404           0 :   RefPtr<DOMSVGLengthList> animVal = mAList->mAnimVal;
     405             : 
     406           0 :   MOZ_ASSERT(animVal, "AnimListMirrorsBaseList() promised a non-null animVal");
     407           0 :   MOZ_ASSERT(animVal->mItems.Length() == mItems.Length(),
     408             :              "animVal list not in sync!");
     409             : 
     410           0 :   if (animVal->mItems[aIndex]) {
     411           0 :     animVal->mItems[aIndex]->RemovingFromList();
     412             :   }
     413           0 :   animVal->mItems.RemoveElementAt(aIndex);
     414             : 
     415           0 :   UpdateListIndicesFromIndex(animVal->mItems, aIndex);
     416             : }
     417             : 
     418             : } // namespace mozilla

Generated by: LCOV version 1.13