LCOV - app.info - content/svg/content/src/DOMSVGPathSegList.cpp

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