LCOV - code coverage report
Current view: directory - content/svg/content/src - DOMSVGPathSegList.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 244 3 1.2 %
Date: 2012-06-02 Functions: 31 2 6.5 %

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

Generated by: LCOV version 1.7