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

Generated by: LCOV version 1.13