LCOV - code coverage report
Current view: directory - content/svg/content/src - DOMSVGLengthList.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 179 2 1.1 %
Date: 2012-06-02 Functions: 26 2 7.7 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is Mozilla SVG Project code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is the Mozilla Foundation.
      18                 :  * Portions created by the Initial Developer are Copyright (C) 2010
      19                 :  * the Initial Developer. All Rights Reserved.
      20                 :  *
      21                 :  * Contributor(s):
      22                 :  *
      23                 :  * Alternatively, the contents of this file may be used under the terms of
      24                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      25                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      26                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      27                 :  * of those above. If you wish to allow use of your version of this file only
      28                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      29                 :  * use your version of this file under the terms of the MPL, indicate your
      30                 :  * decision by deleting the provisions above and replace them with the notice
      31                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      32                 :  * the provisions above, a recipient may use your version of this file under
      33                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      34                 :  *
      35                 :  * ***** END LICENSE BLOCK ***** */
      36                 : 
      37                 : #include "nsSVGElement.h"
      38                 : #include "DOMSVGLengthList.h"
      39                 : #include "DOMSVGLength.h"
      40                 : #include "nsDOMError.h"
      41                 : #include "SVGAnimatedLengthList.h"
      42                 : #include "nsCOMPtr.h"
      43                 : #include "nsContentUtils.h"
      44                 : #include "dombindings.h"
      45                 : 
      46                 : // See the comment in this file's header.
      47                 : 
      48                 : // local helper functions
      49                 : namespace {
      50                 : 
      51                 : using mozilla::DOMSVGLength;
      52                 : 
      53               0 : void UpdateListIndicesFromIndex(nsTArray<DOMSVGLength*>& aItemsArray,
      54                 :                                 PRUint32 aStartingIndex)
      55                 : {
      56               0 :   PRUint32 length = aItemsArray.Length();
      57                 : 
      58               0 :   for (PRUint32 i = aStartingIndex; i < length; ++i) {
      59               0 :     if (aItemsArray[i]) {
      60               0 :       aItemsArray[i]->UpdateListIndex(i);
      61                 :     }
      62                 :   }
      63               0 : }
      64                 : 
      65                 : } // namespace
      66                 : 
      67                 : namespace mozilla {
      68                 : 
      69                 : // We could use NS_IMPL_CYCLE_COLLECTION_1, except that in Unlink() we need to
      70                 : // clear our DOMSVGAnimatedLengthList's weak ref to us to be safe. (The other
      71                 : // option would be to not unlink and rely on the breaking of the other edges in
      72                 : // the cycle, as NS_SVG_VAL_IMPL_CYCLE_COLLECTION does.)
      73            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(DOMSVGLengthList)
      74               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMSVGLengthList)
      75                 :   // No need to null check tmp - script/SMIL can't detach us from mAList
      76               0 :   ( tmp->IsAnimValList() ? tmp->mAList->mAnimVal : tmp->mAList->mBaseVal ) = nsnull;
      77               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mAList)
      78               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
      79               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
      80               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMSVGLengthList)
      81               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mAList)
      82               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
      83               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
      84               0 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMSVGLengthList)
      85               0 :   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
      86               0 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
      87                 : 
      88               0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMSVGLengthList)
      89               0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMSVGLengthList)
      90                 : 
      91                 : } // namespace mozilla
      92                 : DOMCI_DATA(SVGLengthList, mozilla::DOMSVGLengthList)
      93                 : namespace mozilla {
      94                 : 
      95               0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGLengthList)
      96               0 :   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
      97               0 :   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGLengthList)
      98               0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
      99               0 :   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGLengthList)
     100               0 : NS_INTERFACE_MAP_END
     101                 : 
     102                 : JSObject*
     103               0 : DOMSVGLengthList::WrapObject(JSContext *cx, XPCWrappedNativeScope *scope,
     104                 :                              bool *triedToWrap)
     105                 : {
     106                 :   return mozilla::dom::binding::SVGLengthList::create(cx, scope, this,
     107               0 :                                                       triedToWrap);
     108                 : }
     109                 : 
     110                 : nsIDOMSVGLength*
     111               0 : DOMSVGLengthList::GetItemAt(PRUint32 aIndex)
     112                 : {
     113               0 :   if (IsAnimValList()) {
     114               0 :     Element()->FlushAnimations();
     115                 :   }
     116               0 :   if (aIndex < Length()) {
     117               0 :     EnsureItemAt(aIndex);
     118               0 :     return mItems[aIndex];
     119                 :   }
     120               0 :   return nsnull;
     121                 : }
     122                 : 
     123                 : void
     124               0 : DOMSVGLengthList::InternalListLengthWillChange(PRUint32 aNewLength)
     125                 : {
     126               0 :   PRUint32 oldLength = mItems.Length();
     127                 : 
     128               0 :   if (aNewLength > DOMSVGLength::MaxListIndex()) {
     129                 :     // It's safe to get out of sync with our internal list as long as we have
     130                 :     // FEWER items than it does.
     131               0 :     aNewLength = DOMSVGLength::MaxListIndex();
     132                 :   }
     133                 : 
     134               0 :   nsRefPtr<DOMSVGLengthList> kungFuDeathGrip;
     135               0 :   if (aNewLength < oldLength) {
     136                 :     // RemovingFromList() might clear last reference to |this|.
     137                 :     // Retain a temporary reference to keep from dying before returning.
     138               0 :     kungFuDeathGrip = this;
     139                 :   }
     140                 : 
     141                 :   // If our length will decrease, notify the items that will be removed:
     142               0 :   for (PRUint32 i = aNewLength; i < oldLength; ++i) {
     143               0 :     if (mItems[i]) {
     144               0 :       mItems[i]->RemovingFromList();
     145                 :     }
     146                 :   }
     147                 : 
     148               0 :   if (!mItems.SetLength(aNewLength)) {
     149                 :     // We silently ignore SetLength OOM failure since being out of sync is safe
     150                 :     // so long as we have *fewer* items than our internal list.
     151               0 :     mItems.Clear();
     152                 :     return;
     153                 :   }
     154                 : 
     155                 :   // If our length has increased, null out the new pointers:
     156               0 :   for (PRUint32 i = oldLength; i < aNewLength; ++i) {
     157               0 :     mItems[i] = nsnull;
     158                 :   }
     159                 : }
     160                 : 
     161                 : SVGLengthList&
     162               0 : DOMSVGLengthList::InternalList() const
     163                 : {
     164               0 :   SVGAnimatedLengthList *alist = Element()->GetAnimatedLengthList(AttrEnum());
     165               0 :   return IsAnimValList() && alist->mAnimVal ? *alist->mAnimVal : alist->mBaseVal;
     166                 : }
     167                 : 
     168                 : // ----------------------------------------------------------------------------
     169                 : // nsIDOMSVGLengthList implementation:
     170                 : 
     171                 : NS_IMETHODIMP
     172               0 : DOMSVGLengthList::GetNumberOfItems(PRUint32 *aNumberOfItems)
     173                 : {
     174               0 :   if (IsAnimValList()) {
     175               0 :     Element()->FlushAnimations();
     176                 :   }
     177               0 :   *aNumberOfItems = Length();
     178               0 :   return NS_OK;
     179                 : }
     180                 : 
     181                 : NS_IMETHODIMP
     182               0 : DOMSVGLengthList::Clear()
     183                 : {
     184               0 :   if (IsAnimValList()) {
     185               0 :     return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
     186                 :   }
     187                 : 
     188               0 :   if (Length() > 0) {
     189               0 :     nsAttrValue emptyOrOldValue = Element()->WillChangeLengthList(AttrEnum());
     190                 :     // Notify any existing DOM items of removal *before* truncating the lists
     191                 :     // so that they can find their SVGLength internal counterparts and copy
     192                 :     // their values. This also notifies the animVal list:
     193               0 :     mAList->InternalBaseValListWillChangeTo(SVGLengthList());
     194                 : 
     195               0 :     mItems.Clear();
     196               0 :     InternalList().Clear();
     197               0 :     Element()->DidChangeLengthList(AttrEnum(), emptyOrOldValue);
     198               0 :     if (mAList->IsAnimating()) {
     199               0 :       Element()->AnimationNeedsResample();
     200                 :     }
     201                 :   }
     202               0 :   return NS_OK;
     203                 : }
     204                 : 
     205                 : NS_IMETHODIMP
     206               0 : DOMSVGLengthList::Initialize(nsIDOMSVGLength *newItem,
     207                 :                              nsIDOMSVGLength **_retval)
     208                 : {
     209               0 :   *_retval = nsnull;
     210               0 :   if (IsAnimValList()) {
     211               0 :     return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
     212                 :   }
     213                 : 
     214                 :   // If newItem is already in a list we should insert a clone of newItem, and
     215                 :   // for consistency, this should happen even if *this* is the list that
     216                 :   // newItem is currently in. Note that in the case of newItem being in this
     217                 :   // list, the Clear() call before the InsertItemBefore() call would remove it
     218                 :   // from this list, and so the InsertItemBefore() call would not insert a
     219                 :   // clone of newItem, it would actually insert newItem. To prevent that from
     220                 :   // happening we have to do the clone here, if necessary.
     221                 : 
     222               0 :   nsCOMPtr<DOMSVGLength> domItem = do_QueryInterface(newItem);
     223               0 :   if (!domItem) {
     224               0 :     return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
     225                 :   }
     226               0 :   if (domItem->HasOwner()) {
     227               0 :     newItem = domItem->Copy();
     228                 :   }
     229                 : 
     230               0 :   Clear();
     231               0 :   return InsertItemBefore(newItem, 0, _retval);
     232                 : }
     233                 : 
     234                 : NS_IMETHODIMP
     235               0 : DOMSVGLengthList::GetItem(PRUint32 index,
     236                 :                           nsIDOMSVGLength **_retval)
     237                 : {
     238               0 :   *_retval = GetItemAt(index);
     239               0 :   if (!*_retval) {
     240               0 :     return NS_ERROR_DOM_INDEX_SIZE_ERR;
     241                 :   }
     242               0 :   NS_ADDREF(*_retval);
     243               0 :   return NS_OK;
     244                 : }
     245                 : 
     246                 : NS_IMETHODIMP
     247               0 : DOMSVGLengthList::InsertItemBefore(nsIDOMSVGLength *newItem,
     248                 :                                    PRUint32 index,
     249                 :                                    nsIDOMSVGLength **_retval)
     250                 : {
     251               0 :   *_retval = nsnull;
     252               0 :   if (IsAnimValList()) {
     253               0 :     return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
     254                 :   }
     255                 : 
     256               0 :   index = NS_MIN(index, Length());
     257               0 :   if (index >= DOMSVGLength::MaxListIndex()) {
     258               0 :     return NS_ERROR_DOM_INDEX_SIZE_ERR;
     259                 :   }
     260                 : 
     261               0 :   nsCOMPtr<DOMSVGLength> domItem = do_QueryInterface(newItem);
     262               0 :   if (!domItem) {
     263               0 :     return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
     264                 :   }
     265               0 :   if (domItem->HasOwner()) {
     266               0 :     domItem = domItem->Copy(); // must do this before changing anything!
     267                 :   }
     268                 : 
     269                 :   // Ensure we have enough memory so we can avoid complex error handling below:
     270               0 :   if (!mItems.SetCapacity(mItems.Length() + 1) ||
     271               0 :       !InternalList().SetCapacity(InternalList().Length() + 1)) {
     272               0 :     return NS_ERROR_OUT_OF_MEMORY;
     273                 :   }
     274                 : 
     275               0 :   nsAttrValue emptyOrOldValue = Element()->WillChangeLengthList(AttrEnum());
     276                 :   // Now that we know we're inserting, keep animVal list in sync as necessary.
     277               0 :   MaybeInsertNullInAnimValListAt(index);
     278                 : 
     279               0 :   InternalList().InsertItem(index, domItem->ToSVGLength());
     280               0 :   mItems.InsertElementAt(index, domItem.get());
     281                 : 
     282                 :   // This MUST come after the insertion into InternalList(), or else under the
     283                 :   // insertion into InternalList() the values read from domItem would be bad
     284                 :   // data from InternalList() itself!:
     285               0 :   domItem->InsertingIntoList(this, AttrEnum(), index, IsAnimValList());
     286                 : 
     287               0 :   UpdateListIndicesFromIndex(mItems, index + 1);
     288                 : 
     289               0 :   Element()->DidChangeLengthList(AttrEnum(), emptyOrOldValue);
     290               0 :   if (mAList->IsAnimating()) {
     291               0 :     Element()->AnimationNeedsResample();
     292                 :   }
     293               0 :   *_retval = domItem.forget().get();
     294               0 :   return NS_OK;
     295                 : }
     296                 : 
     297                 : NS_IMETHODIMP
     298               0 : DOMSVGLengthList::ReplaceItem(nsIDOMSVGLength *newItem,
     299                 :                               PRUint32 index,
     300                 :                               nsIDOMSVGLength **_retval)
     301                 : {
     302               0 :   *_retval = nsnull;
     303               0 :   if (IsAnimValList()) {
     304               0 :     return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
     305                 :   }
     306                 : 
     307               0 :   nsCOMPtr<DOMSVGLength> domItem = do_QueryInterface(newItem);
     308               0 :   if (!domItem) {
     309               0 :     return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
     310                 :   }
     311               0 :   if (index >= Length()) {
     312               0 :     return NS_ERROR_DOM_INDEX_SIZE_ERR;
     313                 :   }
     314               0 :   if (domItem->HasOwner()) {
     315               0 :     domItem = domItem->Copy(); // must do this before changing anything!
     316                 :   }
     317                 : 
     318               0 :   nsAttrValue emptyOrOldValue = Element()->WillChangeLengthList(AttrEnum());
     319               0 :   if (mItems[index]) {
     320                 :     // Notify any existing DOM item of removal *before* modifying the lists so
     321                 :     // that the DOM item can copy the *old* value at its index:
     322               0 :     mItems[index]->RemovingFromList();
     323                 :   }
     324                 : 
     325               0 :   InternalList()[index] = domItem->ToSVGLength();
     326               0 :   mItems[index] = domItem;
     327                 : 
     328                 :   // This MUST come after the ToSVGPoint() call, otherwise that call
     329                 :   // would end up reading bad data from InternalList()!
     330               0 :   domItem->InsertingIntoList(this, AttrEnum(), index, IsAnimValList());
     331                 : 
     332               0 :   Element()->DidChangeLengthList(AttrEnum(), emptyOrOldValue);
     333               0 :   if (mAList->IsAnimating()) {
     334               0 :     Element()->AnimationNeedsResample();
     335                 :   }
     336               0 :   NS_ADDREF(*_retval = domItem.get());
     337               0 :   return NS_OK;
     338                 : }
     339                 : 
     340                 : NS_IMETHODIMP
     341               0 : DOMSVGLengthList::RemoveItem(PRUint32 index,
     342                 :                              nsIDOMSVGLength **_retval)
     343                 : {
     344               0 :   *_retval = nsnull;
     345               0 :   if (IsAnimValList()) {
     346               0 :     return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
     347                 :   }
     348                 : 
     349               0 :   if (index >= Length()) {
     350               0 :     return NS_ERROR_DOM_INDEX_SIZE_ERR;
     351                 :   }
     352                 : 
     353               0 :   nsAttrValue emptyOrOldValue = Element()->WillChangeLengthList(AttrEnum());
     354                 :   // Now that we know we're removing, keep animVal list in sync as necessary.
     355                 :   // Do this *before* touching InternalList() so the removed item can get its
     356                 :   // internal value.
     357               0 :   MaybeRemoveItemFromAnimValListAt(index);
     358                 : 
     359                 :   // We have to return the removed item, so make sure it exists:
     360               0 :   EnsureItemAt(index);
     361                 : 
     362                 :   // Notify the DOM item of removal *before* modifying the lists so that the
     363                 :   // DOM item can copy its *old* value:
     364               0 :   mItems[index]->RemovingFromList();
     365               0 :   NS_ADDREF(*_retval = mItems[index]);
     366                 : 
     367               0 :   InternalList().RemoveItem(index);
     368               0 :   mItems.RemoveElementAt(index);
     369                 : 
     370               0 :   UpdateListIndicesFromIndex(mItems, index);
     371                 : 
     372               0 :   Element()->DidChangeLengthList(AttrEnum(), emptyOrOldValue);
     373               0 :   if (mAList->IsAnimating()) {
     374               0 :     Element()->AnimationNeedsResample();
     375                 :   }
     376               0 :   return NS_OK;
     377                 : }
     378                 : 
     379                 : NS_IMETHODIMP
     380               0 : DOMSVGLengthList::AppendItem(nsIDOMSVGLength *newItem,
     381                 :                              nsIDOMSVGLength **_retval)
     382                 : {
     383               0 :   return InsertItemBefore(newItem, Length(), _retval);
     384                 : }
     385                 : 
     386                 : NS_IMETHODIMP
     387               0 : DOMSVGLengthList::GetLength(PRUint32 *aNumberOfItems)
     388                 : {
     389               0 :   return GetNumberOfItems(aNumberOfItems);
     390                 : }
     391                 : 
     392                 : void
     393               0 : DOMSVGLengthList::EnsureItemAt(PRUint32 aIndex)
     394                 : {
     395               0 :   if (!mItems[aIndex]) {
     396               0 :     mItems[aIndex] = new DOMSVGLength(this, AttrEnum(), aIndex, IsAnimValList());
     397                 :   }
     398               0 : }
     399                 : 
     400                 : void
     401               0 : DOMSVGLengthList::MaybeInsertNullInAnimValListAt(PRUint32 aIndex)
     402                 : {
     403               0 :   NS_ABORT_IF_FALSE(!IsAnimValList(), "call from baseVal to animVal");
     404                 : 
     405               0 :   DOMSVGLengthList* animVal = mAList->mAnimVal;
     406                 : 
     407               0 :   if (!animVal || mAList->IsAnimating()) {
     408                 :     // No animVal list wrapper, or animVal not a clone of baseVal
     409               0 :     return;
     410                 :   }
     411                 : 
     412               0 :   NS_ABORT_IF_FALSE(animVal->mItems.Length() == mItems.Length(),
     413                 :                     "animVal list not in sync!");
     414                 : 
     415               0 :   animVal->mItems.InsertElementAt(aIndex, static_cast<DOMSVGLength*>(nsnull));
     416                 : 
     417               0 :   UpdateListIndicesFromIndex(animVal->mItems, aIndex + 1);
     418                 : }
     419                 : 
     420                 : void
     421               0 : DOMSVGLengthList::MaybeRemoveItemFromAnimValListAt(PRUint32 aIndex)
     422                 : {
     423               0 :   NS_ABORT_IF_FALSE(!IsAnimValList(), "call from baseVal to animVal");
     424                 : 
     425                 :   // This needs to be a strong reference; otherwise, the RemovingFromList call
     426                 :   // below might drop the last reference to animVal before we're done with it.
     427               0 :   nsRefPtr<DOMSVGLengthList> animVal = mAList->mAnimVal;
     428                 : 
     429               0 :   if (!animVal || mAList->IsAnimating()) {
     430                 :     // No animVal list wrapper, or animVal not a clone of baseVal
     431                 :     return;
     432                 :   }
     433                 : 
     434               0 :   NS_ABORT_IF_FALSE(animVal->mItems.Length() == mItems.Length(),
     435                 :                     "animVal list not in sync!");
     436                 : 
     437               0 :   if (animVal->mItems[aIndex]) {
     438               0 :     animVal->mItems[aIndex]->RemovingFromList();
     439                 :   }
     440               0 :   animVal->mItems.RemoveElementAt(aIndex);
     441                 : 
     442               0 :   UpdateListIndicesFromIndex(animVal->mItems, aIndex);
     443                 : }
     444                 : 
     445            4392 : } // namespace mozilla

Generated by: LCOV version 1.7