Bug 522308 - Add support for SMIL animation of the <polygon> and <polyline> element's 'points' attributes. r=longsonr,dholbert,roc a=roc
authorJonathan Watt <jwatt@jwatt.org>
Wed, 08 Dec 2010 12:15:53 +0000
changeset 58893 10fc5a720ed06d276207b518fcc847650378fa22
parent 58892 6e5bc06304f9f8a6d9b1328c150750513dd32a7f
child 58894 395fac6a7de431827a5254d47ed92c5dafa8b489
push idunknown
push userunknown
push dateunknown
reviewerslongsonr, dholbert, roc, roc
bugs522308
milestone2.0b8pre
Bug 522308 - Add support for SMIL animation of the <polygon> and <polyline> element's 'points' attributes. r=longsonr,dholbert,roc a=roc
content/svg/content/src/DOMSVGPathSeg.h
content/svg/content/src/DOMSVGPoint.cpp
content/svg/content/src/DOMSVGPoint.h
content/svg/content/src/DOMSVGPointList.cpp
content/svg/content/src/DOMSVGPointList.h
content/svg/content/src/Makefile.in
content/svg/content/src/SVGAnimatedPointList.cpp
content/svg/content/src/SVGAnimatedPointList.h
content/svg/content/src/SVGNumberListSMILType.cpp
content/svg/content/src/SVGPoint.h
content/svg/content/src/SVGPointList.cpp
content/svg/content/src/SVGPointList.h
content/svg/content/src/SVGPointListSMILType.cpp
content/svg/content/src/SVGPointListSMILType.h
content/svg/content/src/nsDOMSVGZoomEvent.cpp
content/svg/content/src/nsDOMSVGZoomEvent.h
content/svg/content/src/nsSVGElement.cpp
content/svg/content/src/nsSVGElement.h
content/svg/content/src/nsSVGPathElement.cpp
content/svg/content/src/nsSVGPoint.cpp
content/svg/content/src/nsSVGPoint.h
content/svg/content/src/nsSVGPointList.cpp
content/svg/content/src/nsSVGPointList.h
content/svg/content/src/nsSVGPolyElement.cpp
content/svg/content/src/nsSVGPolyElement.h
content/svg/content/src/nsSVGPolygonElement.cpp
content/svg/content/src/nsSVGSVGElement.cpp
content/svg/content/test/test_SVGxxxList.xhtml
layout/reftests/svg/smil/anim-polygon-points-01-ref.svg
layout/reftests/svg/smil/anim-polygon-points-01.svg
layout/reftests/svg/smil/anim-polyline-points-01-ref.svg
layout/reftests/svg/smil/anim-polyline-points-01.svg
layout/reftests/svg/smil/reftest.list
layout/svg/base/src/nsSVGGlyphFrame.cpp
layout/svg/base/src/nsSVGUtils.cpp
--- a/content/svg/content/src/DOMSVGPathSeg.h
+++ b/content/svg/content/src/DOMSVGPathSeg.h
@@ -77,17 +77,19 @@ class DOMSVGPathSeg : public nsIDOMSVGPa
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(MOZILLA_DOMSVGPATHSEG_IID)
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS(DOMSVGPathSeg)
   NS_DECL_NSIDOMSVGPATHSEG
 
   /**
-   * This convenient factory method creates instances of the correct sub-class.
+   * Unlike the other list classes, we hide our ctor (because no one should be
+   * creating instances of this class directly). This factory method in exposed
+   * instead to take care of creating instances of the correct sub-class.
    */
   static DOMSVGPathSeg *CreateFor(DOMSVGPathSegList *aList,
                                   PRUint32 aListIndex,
                                   PRBool aIsAnimValItem);
 
   /**
    * Create an unowned copy of this object. The caller is responsible for the
    * first AddRef()!
new file mode 100644
--- /dev/null
+++ b/content/svg/content/src/DOMSVGPoint.cpp
@@ -0,0 +1,208 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla SVG Project code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "DOMSVGPoint.h"
+#include "DOMSVGPointList.h"
+#include "SVGPoint.h"
+#include "SVGAnimatedPointList.h"
+#include "nsSVGElement.h"
+#include "nsIDOMSVGPoint.h"
+#include "nsDOMError.h"
+#include "nsIDOMSVGMatrix.h"
+
+// See the architecture comment in DOMSVGPointList.h.
+
+using namespace mozilla;
+
+// We could use NS_IMPL_CYCLE_COLLECTION_1, except that in Unlink() we need to
+// clear our list's weak ref to us to be safe. (The other option would be to
+// not unlink and rely on the breaking of the other edges in the cycle, as
+// NS_SVG_VAL_IMPL_CYCLE_COLLECTION does.)
+NS_IMPL_CYCLE_COLLECTION_CLASS(DOMSVGPoint)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMSVGPoint)
+  // We may not belong to a list, so we must null check tmp->mList.
+  if (tmp->mList) {
+    tmp->mList->mItems[tmp->mListIndex] = nsnull;
+  }
+NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mList)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMSVGPoint)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mList)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMSVGPoint)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMSVGPoint)
+
+DOMCI_DATA(SVGPoint, DOMSVGPoint)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGPoint)
+  NS_INTERFACE_MAP_ENTRY(DOMSVGPoint) // pseudo-interface
+  NS_INTERFACE_MAP_ENTRY(nsIDOMSVGPoint)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGPoint)
+NS_INTERFACE_MAP_END
+
+
+NS_IMETHODIMP
+DOMSVGPoint::GetX(float* aX)
+{
+#ifdef MOZ_SMIL
+  if (mIsAnimValItem && HasOwner()) {
+    Element()->FlushAnimations(); // May make HasOwner() == PR_FALSE
+  }
+#endif
+  *aX = HasOwner() ? InternalItem().mX : mPt.mX;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DOMSVGPoint::SetX(float aX)
+{
+  if (mIsAnimValItem || mIsReadonly) {
+    return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
+  }
+
+  NS_ENSURE_FINITE(aX, NS_ERROR_ILLEGAL_VALUE);
+
+  if (HasOwner()) {
+    InternalItem().mX = aX;
+    Element()->DidChangePointList(PR_TRUE);
+#ifdef MOZ_SMIL
+    if (mList->AttrIsAnimating()) {
+      Element()->AnimationNeedsResample();
+    }
+#endif
+    return NS_OK;
+  }
+  mPt.mX = aX;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DOMSVGPoint::GetY(float* aY)
+{
+#ifdef MOZ_SMIL
+  if (mIsAnimValItem && HasOwner()) {
+    Element()->FlushAnimations(); // May make HasOwner() == PR_FALSE
+  }
+#endif
+  *aY = HasOwner() ? InternalItem().mY : mPt.mY;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DOMSVGPoint::SetY(float aY)
+{
+  if (mIsAnimValItem || mIsReadonly) {
+    return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
+  }
+
+  NS_ENSURE_FINITE(aY, NS_ERROR_ILLEGAL_VALUE);
+
+  if (HasOwner()) {
+    InternalItem().mY = aY;
+    Element()->DidChangePointList(PR_TRUE);
+#ifdef MOZ_SMIL
+    if (mList->AttrIsAnimating()) {
+      Element()->AnimationNeedsResample();
+    }
+#endif
+    return NS_OK;
+  }
+  mPt.mY = aY;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DOMSVGPoint::MatrixTransform(nsIDOMSVGMatrix *matrix,
+                             nsIDOMSVGPoint **_retval)
+{
+  if (!matrix)
+    return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
+
+  float a, b, c, d, e, f;
+  matrix->GetA(&a);
+  matrix->GetB(&b);
+  matrix->GetC(&c);
+  matrix->GetD(&d);
+  matrix->GetE(&e);
+  matrix->GetF(&f);
+
+  float x = HasOwner() ? InternalItem().mX : mPt.mX;
+  float y = HasOwner() ? InternalItem().mY : mPt.mY;
+
+  NS_ADDREF(*_retval = new DOMSVGPoint(a*x + c*y + e, b*x + d*y + f));
+  return NS_OK;
+}
+
+void
+DOMSVGPoint::InsertingIntoList(DOMSVGPointList *aList,
+                               PRUint32 aListIndex,
+                               PRBool aIsAnimValItem)
+{
+  NS_ABORT_IF_FALSE(!HasOwner(), "Inserting item that already has an owner");
+
+  mList = aList;
+  mListIndex = aListIndex;
+  mIsReadonly = PR_FALSE;
+  mIsAnimValItem = aIsAnimValItem;
+
+  NS_ABORT_IF_FALSE(IndexIsValid(), "Bad index for DOMSVGPoint!");
+}
+
+void
+DOMSVGPoint::RemovingFromList()
+{
+  mPt = InternalItem();
+  mList = nsnull;
+  NS_ABORT_IF_FALSE(!mIsReadonly, "mIsReadonly set for list");
+  mIsAnimValItem = PR_FALSE;
+}
+
+SVGPoint&
+DOMSVGPoint::InternalItem()
+{
+  return mList->InternalList().mItems[mListIndex];
+}
+
+#ifdef DEBUG
+PRBool
+DOMSVGPoint::IndexIsValid()
+{
+  return mListIndex < mList->InternalList().Length();
+}
+#endif
+
new file mode 100644
--- /dev/null
+++ b/content/svg/content/src/DOMSVGPoint.h
@@ -0,0 +1,240 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla SVG Project code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef MOZILLA_DOMSVGPOINT_H__
+#define MOZILLA_DOMSVGPOINT_H__
+
+#include "nsIDOMSVGPoint.h"
+#include "DOMSVGPointList.h"
+#include "SVGPoint.h"
+#include "gfxPoint.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsAutoPtr.h"
+
+class nsSVGElement;
+
+// We make DOMSVGPoint a pseudo-interface to allow us to QI to it in order to
+// check that the objects that scripts pass to DOMSVGPointList methods are
+// our *native* point objects.
+//
+// {d6b6c440-af8d-40ee-856b-02a317cab275}
+#define MOZILLA_DOMSVGPOINT_IID \
+  { 0xd6b6c440, 0xaf8d, 0x40ee, \
+    { 0x85, 0x6b, 0x02, 0xa3, 0x17, 0xca, 0xb2, 0x75 } }
+
+namespace mozilla {
+
+/**
+ * Class DOMSVGPoint
+ *
+ * This class creates the DOM objects that wrap internal SVGPoint objects that
+ * are in an SVGPointList. It is also used to create the objects returned by
+ * SVGSVGElement.createSVGPoint() and other functions that return DOM SVGPoint
+ * objects.
+ *
+ * See the architecture comment in DOMSVGPointList.h for an overview of the
+ * important points regarding these DOM wrapper structures.
+ *
+ * See the architecture comment in DOMSVGLength.h (yes, LENGTH) for an overview
+ * of the important points regarding how this specific class works.
+ */
+class DOMSVGPoint : public nsIDOMSVGPoint
+{
+public:
+  NS_DECLARE_STATIC_IID_ACCESSOR(MOZILLA_DOMSVGPOINT_IID)
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS(DOMSVGPoint)
+  NS_DECL_NSIDOMSVGPOINT
+
+  /**
+   * Generic ctor for DOMSVGPoint objects that are created for an attribute.
+   */
+  DOMSVGPoint(DOMSVGPointList *aList,
+              PRUint32 aListIndex,
+              PRBool aIsAnimValItem)
+    : mList(aList)
+    , mListIndex(aListIndex)
+    , mIsReadonly(PR_FALSE)
+    , mIsAnimValItem(aIsAnimValItem)
+  {
+    // These shifts are in sync with the members.
+    NS_ABORT_IF_FALSE(aList &&
+                      aListIndex < (1U << 30), "bad arg");
+
+    NS_ABORT_IF_FALSE(IndexIsValid(), "Bad index for DOMSVGPoint!");
+  }
+
+  DOMSVGPoint(const DOMSVGPoint *aPt = nsnull)
+    : mList(nsnull)
+    , mListIndex(0)
+    , mIsReadonly(PR_FALSE)
+    , mIsAnimValItem(PR_FALSE)
+  {
+    if (aPt) {
+      mPt = aPt->ToSVGPoint();
+    }
+  }
+
+  DOMSVGPoint(float aX, float aY)
+    : mList(nsnull)
+    , mListIndex(0)
+    , mIsReadonly(PR_FALSE)
+    , mIsAnimValItem(PR_FALSE)
+  {
+    mPt.mX = aX;
+    mPt.mY = aY;
+  }
+
+  DOMSVGPoint(const gfxPoint &aPt)
+    : mList(nsnull)
+    , mListIndex(0)
+    , mIsReadonly(PR_FALSE)
+    , mIsAnimValItem(PR_FALSE)
+  {
+    mPt.mX = float(aPt.x);
+    mPt.mY = float(aPt.y);
+    NS_ASSERTION(NS_FloatIsFinite(mPt.mX) && NS_FloatIsFinite(mPt.mX),
+                 "DOMSVGPoint coords are not finite");
+  }
+
+
+  ~DOMSVGPoint() {
+    // Our mList's weak ref to us must be nulled out when we die. If GC has
+    // unlinked us using the cycle collector code, then that has already
+    // happened, and mList is null.
+    if (mList) {
+      mList->mItems[mListIndex] = nsnull;
+    }
+  }
+
+  /**
+   * Create an unowned copy of this object. The caller is responsible for the
+   * first AddRef()!
+   */
+  DOMSVGPoint* Clone() {
+    return new DOMSVGPoint(this);
+  }
+
+  PRBool IsInList() const {
+    return !!mList;
+  }
+
+  /**
+   * In future, if this class is used for non-list points, this will be
+   * different to IsInList(). "Owner" here means that the instance has an
+   * internal counterpart from which it gets its values. (A better name may
+   * be HasWrappee().)
+   */
+  PRBool HasOwner() const {
+    return !!mList;
+  }
+
+  /**
+   * This method is called to notify this DOM object that it is being inserted
+   * into a list, and give it the information it needs as a result.
+   *
+   * This object MUST NOT already belong to a list when this method is called.
+   * That's not to say that script can't move these DOM objects between
+   * lists - it can - it's just that the logic to handle that (and send out
+   * the necessary notifications) is located elsewhere (in DOMSVGPointList).)
+   */
+  void InsertingIntoList(DOMSVGPointList *aList,
+                         PRUint32 aListIndex,
+                         PRBool aIsAnimValItem);
+
+  /// This method is called to notify this object that its list index changed.
+  void UpdateListIndex(PRUint8 aListIndex) {
+    mListIndex = aListIndex;
+  }
+
+  /**
+   * This method is called to notify this DOM object that it is about to be
+   * removed from its current DOM list so that it can first make a copy of its
+   * internal counterpart's values. (If it didn't do this, then it would
+   * "lose" its value on being removed.)
+   */
+  void RemovingFromList();
+
+  SVGPoint ToSVGPoint() const {
+    return HasOwner() ? const_cast<DOMSVGPoint*>(this)->InternalItem() : mPt;
+  }
+
+  PRBool IsReadonly() const {
+    return mIsReadonly;
+  }
+  void SetReadonly(PRBool aReadonly) {
+    mIsReadonly = aReadonly;
+  }
+
+protected:
+
+  nsSVGElement* Element() {
+    return mList->Element();
+  }
+
+  /**
+   * Get a reference to the internal SVGPoint list item that this DOM wrapper
+   * object currently wraps.
+   *
+   * To simplify the code we just have this one method for obtaining both
+   * baseVal and animVal internal items. This means that animVal items don't
+   * get const protection, but then our setter methods guard against changing
+   * animVal items.
+   */
+  SVGPoint& InternalItem();
+
+#ifdef DEBUG
+  PRBool IndexIsValid();
+#endif
+
+  nsRefPtr<DOMSVGPointList> mList;
+
+  // Bounds for the following are checked in the ctor, so be sure to update
+  // that if you change the capacity of any of the following.
+
+  PRUint32 mListIndex:30;
+  PRUint32 mIsReadonly:1;    // PRUint32 because MSVC won't pack otherwise
+  PRUint32 mIsAnimValItem:1; // PRUint32 because MSVC won't pack otherwise
+
+  // The following member is only used when we're not in a list:
+  SVGPoint mPt;
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(DOMSVGPoint, MOZILLA_DOMSVGPOINT_IID)
+
+} // namespace mozilla
+
+#endif // MOZILLA_DOMSVGPOINT_H__
new file mode 100644
--- /dev/null
+++ b/content/svg/content/src/DOMSVGPointList.cpp
@@ -0,0 +1,389 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla SVG Project code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsSVGElement.h"
+#include "DOMSVGPointList.h"
+#include "DOMSVGPoint.h"
+#include "nsDOMError.h"
+#include "SVGAnimatedPointList.h"
+#include "nsCOMPtr.h"
+#include "nsSVGAttrTearoffTable.h"
+
+// See the comment in this file's header.
+
+using namespace mozilla;
+
+static nsSVGAttrTearoffTable<void, DOMSVGPointList>
+  sSVGPointListTearoffTable;
+
+NS_SVG_VAL_IMPL_CYCLE_COLLECTION(DOMSVGPointList, mElement)
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMSVGPointList)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMSVGPointList)
+
+DOMCI_DATA(SVGPointList, DOMSVGPointList)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGPointList)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMSVGPointList)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGPointList)
+NS_INTERFACE_MAP_END
+
+
+/* static */ already_AddRefed<DOMSVGPointList>
+DOMSVGPointList::GetDOMWrapper(void *aList,
+                               nsSVGElement *aElement,
+                               PRBool aIsAnimValList)
+{
+  DOMSVGPointList *wrapper =
+    sSVGPointListTearoffTable.GetTearoff(aList);
+  if (!wrapper) {
+    wrapper = new DOMSVGPointList(aElement, aIsAnimValList);
+    sSVGPointListTearoffTable.AddTearoff(aList, wrapper);
+  }
+  NS_ADDREF(wrapper);
+  return wrapper;
+}
+
+/* static */ DOMSVGPointList*
+DOMSVGPointList::GetDOMWrapperIfExists(void *aList)
+{
+  return sSVGPointListTearoffTable.GetTearoff(aList);
+}
+
+DOMSVGPointList::~DOMSVGPointList()
+{
+  // We no longer have any list items, and there are no script references to
+  // us.
+  //
+  // Do NOT use InternalList() as the key here! That's different!
+  void *key = mIsAnimValList ?
+    InternalAList().GetAnimValKey() :
+    InternalAList().GetBaseValKey();
+  sSVGPointListTearoffTable.RemoveTearoff(key);
+}
+
+void
+DOMSVGPointList::InternalListWillChangeTo(const SVGPointList& aNewValue)
+{
+  // When the number of items in our internal counterpart changes, we MUST stay
+  // in sync. Everything in the scary comment in
+  // DOMSVGLengthList::InternalBaseValListWillChangeTo applies here too!
+
+  PRUint32 oldLength = mItems.Length();
+  PRUint32 newLength = aNewValue.Length();
+
+  // If our length will decrease, notify the items that will be removed:
+  for (PRUint32 i = newLength; i < oldLength; ++i) {
+    if (mItems[i]) {
+      mItems[i]->RemovingFromList();
+    }
+  }
+
+  if (!mItems.SetLength(newLength)) {
+    // We silently ignore SetLength OOM failure since being out of sync is safe
+    // so long as we have *fewer* items than our internal list.
+    mItems.Clear();
+    return;
+  }
+
+  // If our length has increased, null out the new pointers:
+  for (PRUint32 i = oldLength; i < newLength; ++i) {
+    mItems[i] = nsnull;
+  }
+}
+
+PRBool
+DOMSVGPointList::AttrIsAnimating() const
+{
+  return const_cast<DOMSVGPointList*>(this)->InternalAList().IsAnimating();
+}
+
+SVGPointList&
+DOMSVGPointList::InternalList()
+{
+  SVGAnimatedPointList *alist = mElement->GetAnimatedPointList();
+  return mIsAnimValList && alist->IsAnimating() ? *alist->mAnimVal : alist->mBaseVal;
+}
+
+SVGAnimatedPointList&
+DOMSVGPointList::InternalAList()
+{
+  NS_ABORT_IF_FALSE(mElement->GetAnimatedPointList(), "Internal error");
+  return *mElement->GetAnimatedPointList();
+}
+
+// ----------------------------------------------------------------------------
+// nsIDOMSVGPointList implementation:
+
+NS_IMETHODIMP
+DOMSVGPointList::GetNumberOfItems(PRUint32 *aNumberOfItems)
+{
+#ifdef MOZ_SMIL
+  if (IsAnimValList()) {
+    Element()->FlushAnimations();
+  }
+#endif
+  *aNumberOfItems = Length();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DOMSVGPointList::Clear()
+{
+  if (IsAnimValList()) {
+    return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
+  }
+
+  if (Length() > 0) {
+    // DOM list items that are to be removed must be removed before we change
+    // the internal list, otherwise they wouldn't be able to copy their
+    // internal counterparts' values!
+
+    InternalListWillChangeTo(SVGPointList()); // clears mItems
+
+    if (!AttrIsAnimating()) {
+      // The anim val list is in sync with the base val list
+      DOMSVGPointList *animList =
+        GetDOMWrapperIfExists(InternalAList().GetAnimValKey());
+      if (animList) {
+        animList->InternalListWillChangeTo(SVGPointList()); // clears its mItems
+      }
+    }
+
+    InternalList().Clear();
+    Element()->DidChangePointList(PR_TRUE);
+#ifdef MOZ_SMIL
+    if (AttrIsAnimating()) {
+      Element()->AnimationNeedsResample();
+    }
+#endif
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DOMSVGPointList::Initialize(nsIDOMSVGPoint *aNewItem,
+                            nsIDOMSVGPoint **_retval)
+{
+  *_retval = nsnull;
+  if (IsAnimValList()) {
+    return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
+  }
+
+  // If aNewItem is already in a list we should insert a clone of aNewItem,
+  // and for consistency, this should happen even if *this* is the list that
+  // aNewItem is currently in. Note that in the case of aNewItem being in this
+  // list, the Clear() call before the InsertItemBefore() call would remove it
+  // from this list, and so the InsertItemBefore() call would not insert a
+  // clone of aNewItem, it would actually insert aNewItem. To prevent that
+  // from happening we have to do the clone here, if necessary.
+
+  nsCOMPtr<DOMSVGPoint> domItem = do_QueryInterface(aNewItem);
+  if (!domItem) {
+    return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
+  }
+  if (domItem->HasOwner() || domItem->IsReadonly()) {
+    aNewItem = domItem->Clone();
+  }
+
+  Clear();
+  return InsertItemBefore(aNewItem, 0, _retval);
+}
+
+NS_IMETHODIMP
+DOMSVGPointList::GetItem(PRUint32 aIndex,
+                         nsIDOMSVGPoint **_retval)
+{
+#ifdef MOZ_SMIL
+  if (IsAnimValList()) {
+    Element()->FlushAnimations();
+  }
+#endif
+  if (aIndex < Length()) {
+    EnsureItemAt(aIndex);
+    NS_ADDREF(*_retval = mItems[aIndex]);
+    return NS_OK;
+  }
+  *_retval = nsnull;
+  return NS_ERROR_DOM_INDEX_SIZE_ERR;
+}
+
+NS_IMETHODIMP
+DOMSVGPointList::InsertItemBefore(nsIDOMSVGPoint *aNewItem,
+                                  PRUint32 aIndex,
+                                  nsIDOMSVGPoint **_retval)
+{
+  *_retval = nsnull;
+  if (IsAnimValList()) {
+    return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
+  }
+
+  nsCOMPtr<DOMSVGPoint> domItem = do_QueryInterface(aNewItem);
+  if (!domItem) {
+    return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
+  }
+  if (domItem->HasOwner() || domItem->IsReadonly()) {
+    domItem = domItem->Clone(); // must do this before changing anything!
+  }
+  aIndex = NS_MIN(aIndex, mItems.Length());
+
+  // Ensure we have enough memory so we can avoid complex error handling below:
+  if (!mItems.SetCapacity(mItems.Length() + 1) ||
+      !InternalList().SetCapacity(InternalList().Length() + 1)) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  InternalList().InsertItem(aIndex, domItem->ToSVGPoint());
+  mItems.InsertElementAt(aIndex, domItem.get());
+
+  // This MUST come after the insertion into InternalList(), or else the data
+  // read from domItem would be bad data from InternalList() itself!
+  domItem->InsertingIntoList(this, aIndex, IsAnimValList());
+
+  for (PRUint32 i = aIndex + 1; i < Length(); ++i) {
+    if (mItems[i]) {
+      mItems[i]->UpdateListIndex(i);
+    }
+  }
+
+  Element()->DidChangePointList(PR_TRUE);
+#ifdef MOZ_SMIL
+  if (AttrIsAnimating()) {
+    Element()->AnimationNeedsResample();
+  }
+#endif
+  *_retval = domItem.forget().get();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DOMSVGPointList::ReplaceItem(nsIDOMSVGPoint *aNewItem,
+                             PRUint32 aIndex,
+                             nsIDOMSVGPoint **_retval)
+{
+  *_retval = nsnull;
+  if (IsAnimValList()) {
+    return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
+  }
+
+  nsCOMPtr<DOMSVGPoint> domItem = do_QueryInterface(aNewItem);
+  if (!domItem) {
+    return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
+  }
+  if (aIndex >= Length()) {
+    return NS_ERROR_DOM_INDEX_SIZE_ERR;
+  }
+  if (domItem->HasOwner() || domItem->IsReadonly()) {
+    domItem = domItem->Clone(); // must do this before changing anything!
+  }
+
+  if (mItems[aIndex]) {
+    // Notify any existing DOM item of removal *before* modifying the lists so
+    // that the DOM item can copy the *old* value at its index:
+    mItems[aIndex]->RemovingFromList();
+  }
+
+  InternalList()[aIndex] = domItem->ToSVGPoint();
+  mItems[aIndex] = domItem;
+
+  // This MUST come after the assignment to InternalList, otherwise that call
+  // would end up reading bad data from InternalList()!
+  domItem->InsertingIntoList(this, aIndex, IsAnimValList());
+
+  Element()->DidChangePointList(PR_TRUE);
+#ifdef MOZ_SMIL
+  if (AttrIsAnimating()) {
+    Element()->AnimationNeedsResample();
+  }
+#endif
+  NS_ADDREF(*_retval = domItem.get());
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DOMSVGPointList::RemoveItem(PRUint32 aIndex,
+                            nsIDOMSVGPoint **_retval)
+{
+  *_retval = nsnull;
+  if (IsAnimValList()) {
+    return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
+  }
+
+  if (aIndex >= Length()) {
+    return NS_ERROR_DOM_INDEX_SIZE_ERR;
+  }
+  // We have to return the removed item, so make sure it exists:
+  EnsureItemAt(aIndex);
+
+  // Notify the DOM item of removal *before* modifying the lists so that the
+  // DOM item can copy its *old* value:
+  mItems[aIndex]->RemovingFromList();
+  NS_ADDREF(*_retval = mItems[aIndex]);
+
+  InternalList().RemoveItem(aIndex);
+  mItems.RemoveElementAt(aIndex);
+
+  for (PRUint32 i = aIndex; i < Length(); ++i) {
+    if (mItems[i]) {
+      mItems[i]->UpdateListIndex(i);
+    }
+  }
+
+  Element()->DidChangePointList(PR_TRUE);
+#ifdef MOZ_SMIL
+  if (AttrIsAnimating()) {
+    Element()->AnimationNeedsResample();
+  }
+#endif
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DOMSVGPointList::AppendItem(nsIDOMSVGPoint *aNewItem,
+                            nsIDOMSVGPoint **_retval)
+{
+  return InsertItemBefore(aNewItem, Length(), _retval);
+}
+
+void
+DOMSVGPointList::EnsureItemAt(PRUint32 aIndex)
+{
+  if (!mItems[aIndex]) {
+    mItems[aIndex] = new DOMSVGPoint(this, aIndex, IsAnimValList());
+  }
+}
+
new file mode 100644
--- /dev/null
+++ b/content/svg/content/src/DOMSVGPointList.h
@@ -0,0 +1,210 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla SVG Project code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef MOZILLA_DOMSVGPOINTLIST_H__
+#define MOZILLA_DOMSVGPOINTLIST_H__
+
+#include "nsIDOMSVGPointList.h"
+#include "SVGPointList.h"
+#include "SVGPoint.h"
+#include "nsCOMArray.h"
+#include "nsAutoPtr.h"
+
+class nsSVGElement;
+
+namespace mozilla {
+
+class DOMSVGPoint;
+class SVGAnimatedPointList;
+
+/**
+ * Class DOMSVGPointList
+ *
+ * This class is used to create the DOM tearoff objects that wrap internal
+ * SVGPointList objects.
+ *
+ * See the architecture comment in DOMSVGAnimatedLengthList.h first (that's
+ * LENGTH list), then continue reading the remainder of this comment.
+ *
+ * The architecture of this class is very similar to that of DOMSVGLengthList
+ * except that, since there is no nsIDOMSVGAnimatedPointList interface
+ * in SVG, we have no parent DOMSVGAnimatedPointList (unlike DOMSVGLengthList
+ * which has a parent DOMSVGAnimatedLengthList class). (There is an
+ * SVGAnimatedPoints interface, but that is quite different to
+ * DOMSVGAnimatedLengthList, since it is inherited by elements rather than
+ * elements having members of that type.) As a consequence, much of the logic
+ * that would otherwise be in DOMSVGAnimatedPointList (and is in
+ * DOMSVGAnimatedLengthList) is contained in this class.
+ *
+ * This class is strongly intertwined with DOMSVGPoint. Our DOMSVGPoint
+ * items are friends of us and responsible for nulling out our pointers to
+ * them when they die.
+ *
+ * Our DOM items are created lazily on demand as and when script requests them.
+ */
+class DOMSVGPointList : public nsIDOMSVGPointList
+{
+  friend class DOMSVGPoint;
+
+public:
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS(DOMSVGPointList)
+  NS_DECL_NSIDOMSVGPOINTLIST
+
+  /**
+   * Factory method to create and return a DOMSVGPointList wrapper
+   * for a given internal SVGPointList object. The factory takes care
+   * of caching the object that it returns so that the same object can be
+   * returned for the given SVGPointList each time it is requested.
+   * The cached object is only removed from the cache when it is destroyed due
+   * to there being no more references to it or to any of its descendant
+   * objects. If that happens, any subsequent call requesting the DOM wrapper
+   * for the SVGPointList will naturally result in a new
+   * DOMSVGPointList being returned.
+   *
+   * It's unfortunate that aList is a void* instead of a typed argument. This
+   * is because the mBaseVal and mAnimVal members of SVGAnimatedPointList are
+   * of different types - a plain SVGPointList, and a SVGPointList*. We
+   * use the addresses of these members as the key for the hash table, and
+   * clearly SVGPointList* and a SVGPointList** are not the same type.
+   */
+  static already_AddRefed<DOMSVGPointList>
+  GetDOMWrapper(void *aList,
+                nsSVGElement *aElement,
+                PRBool aIsAnimValList);
+
+  /**
+   * This method returns the DOMSVGPointList wrapper for an internal
+   * SVGPointList object if it currently has a wrapper. If it does
+   * not, then nsnull is returned.
+   */
+  static DOMSVGPointList*
+  GetDOMWrapperIfExists(void *aList);
+
+  /**
+   * This will normally be the same as InternalList().Length(), except if
+   * we've hit OOM, in which case our length will be zero.
+   */
+  PRUint32 Length() const {
+    NS_ABORT_IF_FALSE(mItems.Length() == 0 ||
+                      mItems.Length() ==
+                        const_cast<DOMSVGPointList*>(this)->InternalList().Length(),
+                      "DOM wrapper's list length is out of sync");
+    return mItems.Length();
+  }
+
+  /**
+   * WATCH OUT! If you add code to call this on a baseVal wrapper, then you
+   * must also call it on the animVal wrapper too if necessary!! See other
+   * callers!
+   *
+   * Called by internal code to notify us when we need to sync the length of
+   * this DOM list with its internal list. This is called immediately prior to
+   * the length of the internal list being changed so that any DOM list items
+   * that need to be removed from the DOM list can first copy their values from
+   * their internal counterpart.
+   *
+   * The only time this method could fail is on OOM when trying to increase the
+   * length of the DOM list. If that happens then this method simply clears the
+   * list and returns. Callers just proceed as normal, and we simply accept
+   * that the DOM list will be empty (until successfully set to a new value).
+   */
+  void InternalListWillChangeTo(const SVGPointList& aNewValue);
+
+  /**
+   * Returns true if our attribute is animating (in which case our animVal is
+   * not simply a mirror of our baseVal).
+   */
+  PRBool AttrIsAnimating() const;
+
+private:
+
+  /**
+   * Only our static GetDOMWrapper() factory method may create objects of our
+   * type.
+   */
+  DOMSVGPointList(nsSVGElement *aElement, PRBool aIsAnimValList)
+    : mElement(aElement)
+    , mIsAnimValList(aIsAnimValList)
+  {
+    // This call populates mItems with the same number of items as there are
+    // points in the internal list. We ignore OOM failure since being out of
+    // sync is safe so long as we have *fewer* items than our internal list.
+
+    InternalListWillChangeTo(InternalList());
+  }
+
+  ~DOMSVGPointList();
+
+  nsSVGElement* Element() {
+    return mElement.get();
+  }
+
+  /// Used to determine if this list is the baseVal or animVal list.
+  PRBool IsAnimValList() const {
+    return mIsAnimValList;
+  }
+
+  /**
+   * Get a reference to this object's corresponding internal SVGPointList.
+   *
+   * To simplify the code we just have this one method for obtaining both
+   * base val and anim val internal lists. This means that anim val lists don't
+   * get const protection, but our setter methods guard against changing
+   * anim val lists.
+   */
+  SVGPointList& InternalList();
+
+  SVGAnimatedPointList& InternalAList();
+
+  /// Creates an instance of the appropriate DOMSVGPoint sub-class for
+  // aIndex, if it doesn't already exist.
+  void EnsureItemAt(PRUint32 aIndex);
+
+  // Weak refs to our DOMSVGPoint items. The items are friends and take care
+  // of clearing our pointer to them when they die.
+  nsTArray<DOMSVGPoint*> mItems;
+
+  // Strong ref to our element to keep it alive. We hold this not only for
+  // ourself, but also for our DOMSVGPoint items too.
+  nsRefPtr<nsSVGElement> mElement;
+
+  PRPackedBool mIsAnimValList;
+};
+
+} // namespace mozilla
+
+#endif // MOZILLA_DOMSVGPOINTLIST_H__
--- a/content/svg/content/src/Makefile.in
+++ b/content/svg/content/src/Makefile.in
@@ -52,16 +52,18 @@ CPPSRCS		= \
 		DOMSVGAnimatedLengthList.cpp \
 		DOMSVGAnimatedNumberList.cpp \
 		DOMSVGLength.cpp \
 		DOMSVGLengthList.cpp \
 		DOMSVGNumber.cpp \
 		DOMSVGNumberList.cpp \
 		DOMSVGPathSeg.cpp \
 		DOMSVGPathSegList.cpp \
+		DOMSVGPoint.cpp \
+		DOMSVGPointList.cpp \
 		nsDOMSVGZoomEvent.cpp \
 		nsDOMSVGEvent.cpp \
 		nsSVGAElement.cpp \
 		nsSVGAltGlyphElement.cpp \
 		nsSVGAngle.cpp \
 		nsSVGAnimatedTransformList.cpp \
 		nsSVGBoolean.cpp \
 		nsSVGCircleElement.cpp \
@@ -88,18 +90,16 @@ CPPSRCS		= \
 		nsSVGMaskElement.cpp \
 		nsSVGMatrix.cpp \
 		nsSVGMetadataElement.cpp \
 		nsSVGNumber2.cpp \
 		nsSVGPathDataParser.cpp \
 		nsSVGPathElement.cpp \
 		nsSVGPathGeometryElement.cpp \
 		nsSVGPatternElement.cpp \
-		nsSVGPoint.cpp \
-		nsSVGPointList.cpp \
 		nsSVGPolyElement.cpp \
 		nsSVGPolygonElement.cpp \
 		nsSVGPolylineElement.cpp \
 		nsSVGPreserveAspectRatio.cpp \
 		nsSVGScriptElement.cpp \
 		nsSVGString.cpp \
 		nsSVGStringProxyValue.cpp \
 		nsSVGStylableElement.cpp \
@@ -120,21 +120,23 @@ CPPSRCS		= \
 		nsSVGTransformList.cpp \
 		nsSVGTransformListParser.cpp \
 		nsSVGUseElement.cpp \
 		nsSVGValue.cpp \
 		nsSVGViewBox.cpp \
 		SVGAnimatedLengthList.cpp \
 		SVGAnimatedNumberList.cpp \
 		SVGAnimatedPathSegList.cpp \
+		SVGAnimatedPointList.cpp \
 		SVGLength.cpp \
 		SVGLengthList.cpp \
 		SVGNumberList.cpp \
 		SVGPathData.cpp \
 		SVGPathSegUtils.cpp \
+		SVGPointList.cpp \
 		$(NULL)
 
 ifdef MOZ_SMIL
 CPPSRCS += nsSVGAnimateElement.cpp \
            nsSVGAnimateTransformElement.cpp \
            nsSVGAnimateMotionElement.cpp \
            nsSVGAnimationElement.cpp \
            nsSVGMpathElement.cpp \
@@ -144,32 +146,32 @@ CPPSRCS += nsSVGAnimateElement.cpp \
            SVGLengthListSMILType.cpp \
            SVGMotionSMILType.cpp \
            SVGMotionSMILAttr.cpp \
            SVGMotionSMILAnimationFunction.cpp \
            SVGMotionSMILPathUtils.cpp \
            SVGNumberListSMILType.cpp \
            SVGOrientSMILType.cpp \
            SVGPathSegListSMILType.cpp \
+           SVGPointListSMILType.cpp \
            SVGViewBoxSMILType.cpp \
            $(NULL)
 endif
 
 include $(topsrcdir)/config/config.mk
 
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 EXPORTS =  			\
 	nsISVGValue.h              \
 	nsISVGValueObserver.h      \
 	nsISVGValueUtils.h         \
 	nsSVGFeatures.h            \
 	nsSVGRect.h                \
-	nsSVGPoint.h               \
 	nsSVGMatrix.h              \
 	$(NULL)
 
 include $(topsrcdir)/config/rules.mk
 
 INCLUDES += 	\
 		-I$(srcdir)/../../../shared/public \
 		-I$(srcdir)/../../../html/base/src \
new file mode 100644
--- /dev/null
+++ b/content/svg/content/src/SVGAnimatedPointList.cpp
@@ -0,0 +1,243 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla SVG Project code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "SVGAnimatedPointList.h"
+#include "DOMSVGPointList.h"
+#include "nsSVGElement.h"
+#include "nsSVGAttrTearoffTable.h"
+#ifdef MOZ_SMIL
+#include "nsSMILValue.h"
+#include "SVGPointListSMILType.h"
+#endif // MOZ_SMIL
+
+// See the comments in this file's header!
+
+using namespace mozilla;
+
+nsresult
+SVGAnimatedPointList::SetBaseValueString(const nsAString& aValue)
+{
+  SVGPointList newBaseValue;
+
+  // The spec says that the point data is parsed and accepted up to the first
+  // error encountered, so we don't return early if an error occurs. However,
+  // we do want to throw any error code from setAttribute if there's a problem.
+
+  nsresult rv = newBaseValue.SetValueFromString(aValue);
+
+  // We must send these notifications *before* changing mBaseVal! Our baseVal's
+  // DOM wrapper list may have to remove DOM items from itself, and any removed
+  // DOM items need to copy their internal counterpart's values *before* we
+  // change them. See the comments in
+  // DOMSVGPointList::InternalListWillChangeTo().
+
+  DOMSVGPointList *baseValWrapper =
+    DOMSVGPointList::GetDOMWrapperIfExists(GetBaseValKey());
+  if (baseValWrapper) {
+    baseValWrapper->InternalListWillChangeTo(newBaseValue);
+  }
+
+  DOMSVGPointList *animValWrapper;
+  if (!IsAnimating()) {  // DOM anim val wraps our base val too!
+    animValWrapper = DOMSVGPointList::GetDOMWrapperIfExists(GetAnimValKey());
+    if (animValWrapper) {
+      animValWrapper->InternalListWillChangeTo(newBaseValue);
+    }
+  }
+
+  // Only now may we modify mBaseVal!
+
+  // We don't need to call DidChange* here - we're only called by
+  // nsSVGElement::ParseAttribute under nsGenericElement::SetAttr,
+  // which takes care of notifying.
+
+  nsresult rv2 = mBaseVal.CopyFrom(newBaseValue);
+  if (NS_FAILED(rv2)) {
+    // Attempting to increase mBaseVal's length failed (mBaseVal is left
+    // unmodified). We MUST keep any DOM wrappers in sync:
+    if (baseValWrapper) {
+      baseValWrapper->InternalListWillChangeTo(mBaseVal);
+    }
+    if (animValWrapper) {
+      animValWrapper->InternalListWillChangeTo(mBaseVal);
+    }
+    return rv2;
+  }
+  return rv;
+}
+
+void
+SVGAnimatedPointList::ClearBaseValue()
+{
+  // We must send these notifications *before* changing mBaseVal! (See above.)
+
+  DOMSVGPointList *baseValWrapper =
+    DOMSVGPointList::GetDOMWrapperIfExists(GetBaseValKey());
+  if (baseValWrapper) {
+    baseValWrapper->InternalListWillChangeTo(SVGPointList());
+  }
+
+  if (!IsAnimating()) { // DOM anim val wraps our base val too!
+    DOMSVGPointList *animValWrapper =
+      DOMSVGPointList::GetDOMWrapperIfExists(GetAnimValKey());
+    if (animValWrapper) {
+      animValWrapper->InternalListWillChangeTo(SVGPointList());
+    }
+  }
+
+  mBaseVal.Clear();
+  // Caller notifies
+}
+
+nsresult
+SVGAnimatedPointList::SetAnimValue(const SVGPointList& aNewAnimValue,
+                                   nsSVGElement *aElement)
+{
+  // Note that a new animation may totally change the number of items in the
+  // animVal list, either replacing what was essentially a mirror of the
+  // baseVal list, or else replacing and overriding an existing animation.
+  // It is not possible for us to reliably distinguish between calls to this
+  // method that are setting a new sample for an existing animation (in which
+  // case our list length isn't changing and we wouldn't need to notify our DOM
+  // wrapper to keep its length in sync), and calls to this method that are
+  // setting the first sample of a new animation that will override the base
+  // value/an existing animation (in which case our length may be changing and
+  // our DOM wrapper may need to be notified). Happily though, it's cheap to
+  // just blindly notify our animVal's DOM wrapper of our new value each time
+  // this method is called, so that's what we do.
+
+  // We must send this notification *before* changing mAnimVal! (See above.)
+
+  DOMSVGPointList *domWrapper =
+    DOMSVGPointList::GetDOMWrapperIfExists(GetAnimValKey());
+  if (domWrapper) {
+    domWrapper->InternalListWillChangeTo(aNewAnimValue);
+  }
+  if (!mAnimVal) {
+    mAnimVal = new SVGPointList();
+  }
+  nsresult rv = mAnimVal->CopyFrom(aNewAnimValue);
+  if (NS_FAILED(rv)) {
+    // OOM. We clear the animation and, importantly, ClearAnimValue() ensures
+    // that mAnimVal's DOM wrapper (if any) is kept in sync!
+    ClearAnimValue(aElement);
+    return rv;
+  }
+  aElement->DidAnimatePointList();
+  return NS_OK;
+}
+
+void
+SVGAnimatedPointList::ClearAnimValue(nsSVGElement *aElement)
+{
+  // We must send these notifications *before* changing mAnimVal! (See above.)
+
+  DOMSVGPointList *domWrapper =
+    DOMSVGPointList::GetDOMWrapperIfExists(GetAnimValKey());
+  if (domWrapper) {
+    // When all animation ends, animVal simply mirrors baseVal, which may have
+    // a different number of items to the last active animated value.
+    //
+    domWrapper->InternalListWillChangeTo(mBaseVal);
+  }
+  mAnimVal = nsnull;
+  aElement->DidAnimatePointList();
+}
+
+#ifdef MOZ_SMIL
+nsISMILAttr*
+SVGAnimatedPointList::ToSMILAttr(nsSVGElement *aElement)
+{
+  return new SMILAnimatedPointList(this, aElement);
+}
+
+nsresult
+SVGAnimatedPointList::
+  SMILAnimatedPointList::ValueFromString(const nsAString& aStr,
+                               const nsISMILAnimationElement* /*aSrcElement*/,
+                               nsSMILValue& aValue,
+                               PRBool& aPreventCachingOfSandwich) const
+{
+  nsSMILValue val(&SVGPointListSMILType::sSingleton);
+  SVGPointListAndInfo *list = static_cast<SVGPointListAndInfo*>(val.mU.mPtr);
+  nsresult rv = list->SetValueFromString(aStr);
+  if (NS_SUCCEEDED(rv)) {
+    list->SetInfo(mElement);
+    aValue.Swap(val);
+  }
+  aPreventCachingOfSandwich = PR_FALSE;
+  return rv;
+}
+
+nsSMILValue
+SVGAnimatedPointList::SMILAnimatedPointList::GetBaseValue() const
+{
+  // To benefit from Return Value Optimization and avoid copy constructor calls
+  // due to our use of return-by-value, we must return the exact same object
+  // from ALL return points. This function must only return THIS variable:
+  nsSMILValue val;
+
+  nsSMILValue tmp(&SVGPointListSMILType::sSingleton);
+  SVGPointListAndInfo *list = static_cast<SVGPointListAndInfo*>(tmp.mU.mPtr);
+  nsresult rv = list->CopyFrom(mVal->mBaseVal);
+  if (NS_SUCCEEDED(rv)) {
+    list->SetInfo(mElement);
+    val.Swap(tmp);
+  }
+  return val;
+}
+
+nsresult
+SVGAnimatedPointList::SMILAnimatedPointList::SetAnimValue(const nsSMILValue& aValue)
+{
+  NS_ASSERTION(aValue.mType == &SVGPointListSMILType::sSingleton,
+               "Unexpected type to assign animated value");
+  if (aValue.mType == &SVGPointListSMILType::sSingleton) {
+    mVal->SetAnimValue(*static_cast<SVGPointListAndInfo*>(aValue.mU.mPtr),
+                       mElement);
+  }
+  return NS_OK;
+}
+
+void
+SVGAnimatedPointList::SMILAnimatedPointList::ClearAnimValue()
+{
+  if (mVal->mAnimVal) {
+    mVal->ClearAnimValue(mElement);
+  }
+}
+#endif // MOZ_SMIL
+
new file mode 100644
--- /dev/null
+++ b/content/svg/content/src/SVGAnimatedPointList.h
@@ -0,0 +1,160 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla SVG Project code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef MOZILLA_SVGANIMATEDPOINTLIST_H__
+#define MOZILLA_SVGANIMATEDPOINTLIST_H__
+
+#include "SVGPointList.h"
+
+class nsSVGElement;
+
+#ifdef MOZ_SMIL
+#include "nsISMILAttr.h"
+#endif // MOZ_SMIL
+
+namespace mozilla {
+
+/**
+ * Class SVGAnimatedPointList
+ *
+ * Despite the fact that no SVGAnimatedPointList interface or objects exist
+ * in the SVG specification (unlike e.g. SVGAnimated*Length*List), we
+ * nevertheless have this internal class. (Note that there is an
+ * SVGAnimatedPoints interface, but that's quite different to
+ * SVGAnimatedLengthList since it is inherited by elements, as opposed to
+ * elements having members of that type.) The reason that we have this class is
+ * to provide a single locked down point of entry to the SVGPointList objects,
+ * which helps ensure that the DOM wrappers for SVGPointList objects' are
+ * always kept in sync. This is vitally important (see the comment in
+ * DOMSVGPointList::InternalListWillChangeTo) and frees consumers from having
+ * to know or worry about wrappers (or forget about them!) for the most part.
+ */
+class SVGAnimatedPointList
+{
+  // friends so that they can get write access to mBaseVal and mAnimVal
+  friend class DOMSVGPoint;
+  friend class DOMSVGPointList;
+
+public:
+  SVGAnimatedPointList() {}
+
+  /**
+   * Because it's so important that mBaseVal and its DOMSVGPointList wrapper
+   * (if any) be kept in sync (see the comment in
+   * DOMSVGPointList::InternalListWillChangeTo), this method returns a const
+   * reference. Only our friend classes may get mutable references to mBaseVal.
+   */
+  const SVGPointList& GetBaseValue() const {
+    return mBaseVal;
+  }
+
+  nsresult SetBaseValueString(const nsAString& aValue);
+
+  void ClearBaseValue();
+
+  /**
+   * const! See comment for GetBaseValue!
+   */
+  const SVGPointList& GetAnimValue() const {
+    return mAnimVal ? *mAnimVal : mBaseVal;
+  }
+
+  nsresult SetAnimValue(const SVGPointList& aValue,
+                        nsSVGElement *aElement);
+
+  void ClearAnimValue(nsSVGElement *aElement);
+
+  /**
+   * Needed for correct DOM wrapper construction since GetAnimValue may
+   * actually return the baseVal!
+   */
+  void *GetBaseValKey() const {
+    return (void*)&mBaseVal;
+  }
+  void *GetAnimValKey() const {
+    return (void*)&mAnimVal;
+  }
+
+  PRBool IsAnimating() const {
+    return !!mAnimVal;
+  }
+
+#ifdef MOZ_SMIL
+  /// Callers own the returned nsISMILAttr
+  nsISMILAttr* ToSMILAttr(nsSVGElement* aElement);
+#endif // MOZ_SMIL
+
+private:
+
+  // mAnimVal is a pointer to allow us to determine if we're being animated or
+  // not. Making it a non-pointer member and using mAnimVal.IsEmpty() to check
+  // if we're animating is not an option, since that would break animation *to*
+  // the empty string (<set to="">).
+
+  SVGPointList mBaseVal;
+  nsAutoPtr<SVGPointList> mAnimVal;
+
+#ifdef MOZ_SMIL
+  struct SMILAnimatedPointList : public nsISMILAttr
+  {
+  public:
+    SMILAnimatedPointList(SVGAnimatedPointList* aVal,
+                          nsSVGElement* aElement)
+      : mVal(aVal)
+      , mElement(aElement)
+    {}
+
+    // These will stay alive because a nsISMILAttr only lives as long
+    // as the Compositing step, and DOM elements don't get a chance to
+    // die during that.
+    SVGAnimatedPointList *mVal;
+    nsSVGElement *mElement;
+
+    // nsISMILAttr methods
+    virtual nsresult ValueFromString(const nsAString& aStr,
+                                     const nsISMILAnimationElement* aSrcElement,
+                                     nsSMILValue& aValue,
+                                     PRBool& aPreventCachingOfSandwich) const;
+    virtual nsSMILValue GetBaseValue() const;
+    virtual void ClearAnimValue();
+    virtual nsresult SetAnimValue(const nsSMILValue& aValue);
+  };
+#endif // MOZ_SMIL
+};
+
+} // namespace mozilla
+
+#endif // MOZILLA_SVGANIMATEDPOINTLIST_H__
--- a/content/svg/content/src/SVGNumberListSMILType.cpp
+++ b/content/svg/content/src/SVGNumberListSMILType.cpp
@@ -167,17 +167,16 @@ SVGNumberListSMILType::ComputeDistance(c
   const SVGNumberListAndInfo& from =
     *static_cast<const SVGNumberListAndInfo*>(aFrom.mU.mPtr);
   const SVGNumberListAndInfo& to =
     *static_cast<const SVGNumberListAndInfo*>(aTo.mU.mPtr);
 
   if (from.Length() != to.Length()) {
     // Lists in the 'values' attribute must have the same length.
     // nsSVGUtils::ReportToConsole
-    aDistance = 0.0;
     return NS_ERROR_FAILURE;
   }
 
   // We return the root of the sum of the squares of the delta between the
   // numbers at each correspanding index.
 
   double total = 0.0;
 
new file mode 100644
--- /dev/null
+++ b/content/svg/content/src/SVGPoint.h
@@ -0,0 +1,130 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla SVG Project code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef MOZILLA_SVGPOINT_H__
+#define MOZILLA_SVGPOINT_H__
+
+#include "nsDebug.h"
+#include "nsContentUtils.h"
+#include "gfxPoint.h"
+
+namespace mozilla {
+
+/**
+ * This class is currently used for point list attributes.
+ *
+ * The DOM wrapper class for this class is DOMSVGPoint.
+ */
+class SVGPoint
+{
+public:
+
+  SVGPoint()
+#ifdef DEBUG
+    : mX(0.0f)
+    , mY(0.0f)
+#endif
+  {}
+
+  SVGPoint(float aX, float aY)
+    : mX(aX)
+    , mY(aY)
+  {
+    NS_ASSERTION(IsValid(), "Constructed an invalid SVGPoint");
+  }
+
+  SVGPoint(const SVGPoint &aOther)
+    : mX(aOther.mX)
+    , mY(aOther.mY)
+  {}
+
+  SVGPoint& operator=(const SVGPoint &rhs) {
+    mX = rhs.mX;
+    mY = rhs.mY;
+    return *this;
+  }
+
+  PRBool operator==(const SVGPoint &rhs) const {
+    return mX == rhs.mX && mY == rhs.mY;
+  }
+
+  SVGPoint& operator+=(const SVGPoint &rhs) {
+    mX += rhs.mX;
+    mY += rhs.mY;
+    return *this;
+  }
+
+  operator gfxPoint() const {
+    return gfxPoint(mX, mY);
+  }
+
+#ifdef DEBUG
+  PRBool IsValid() const {
+    return NS_FloatIsFinite(mX) && NS_FloatIsFinite(mY);
+  }
+#endif
+
+  float mX;
+  float mY;
+};
+
+inline SVGPoint operator+(const SVGPoint& aP1,
+                          const SVGPoint& aP2)
+{
+  return SVGPoint(aP1.mX + aP2.mX, aP1.mY + aP2.mY);
+}
+
+inline SVGPoint operator-(const SVGPoint& aP1,
+                          const SVGPoint& aP2)
+{
+  return SVGPoint(aP1.mX - aP2.mX, aP1.mY - aP2.mY);
+}
+
+inline SVGPoint operator*(float aFactor,
+                          const SVGPoint& aPoint)
+{
+  return SVGPoint(aFactor * aPoint.mX, aFactor * aPoint.mY);
+}
+
+inline SVGPoint operator*(const SVGPoint& aPoint,
+                          float aFactor)
+{
+  return SVGPoint(aFactor * aPoint.mX, aFactor * aPoint.mY);
+}
+
+} // namespace mozilla
+
+#endif // MOZILLA_SVGPOINT_H__
new file mode 100644
--- /dev/null
+++ b/content/svg/content/src/SVGPointList.cpp
@@ -0,0 +1,143 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla SVG Project code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "SVGPointList.h"
+#include "SVGAnimatedPointList.h"
+#include "nsSVGElement.h"
+#include "nsISVGValueUtils.h"
+#include "nsDOMError.h"
+#include "nsContentUtils.h"
+#include "nsString.h"
+#include "nsSVGUtils.h"
+#include "string.h"
+#include "prdtoa.h"
+#include "nsTextFormatter.h"
+#include "nsCharSeparatedTokenizer.h"
+
+using namespace mozilla;
+
+nsresult
+SVGPointList::CopyFrom(const SVGPointList& rhs)
+{
+  if (!SetCapacity(rhs.Length())) {
+    // Yes, we do want fallible alloc here
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+  mItems = rhs.mItems;
+  return NS_OK;
+}
+
+void
+SVGPointList::GetValueAsString(nsAString& aValue) const
+{
+  aValue.Truncate();
+  PRUnichar buf[50];
+  PRUint32 last = mItems.Length() - 1;
+  for (PRUint32 i = 0; i < mItems.Length(); ++i) {
+    // Would like to use aValue.AppendPrintf("%f,%f", item.mX, item.mY),
+    // but it's not possible to always avoid trailing zeros.
+    nsTextFormatter::snprintf(buf, NS_ARRAY_LENGTH(buf),
+                              NS_LITERAL_STRING("%g,%g").get(),
+                              double(mItems[i].mX), double(mItems[i].mY));
+    // We ignore OOM, since it's not useful for us to return an error.
+    aValue.Append(buf);
+    if (i != last) {
+      aValue.Append(' ');
+    }
+  }
+}
+
+static inline char* SkipWhitespace(char* str)
+{
+  while (IsSVGWhitespace(*str))
+    ++str;
+  return str;
+}
+
+nsresult
+SVGPointList::SetValueFromString(const nsAString& aValue)
+{
+  // The spec says that the list is parsed and accepted up to the first error
+  // encountered, so we must call CopyFrom even if an error occurs. We still
+  // want to throw any error code from setAttribute if there's a problem
+  // though, so we must take care to return any error code.
+
+  nsresult rv = NS_OK;
+
+  SVGPointList temp;
+
+  nsCharSeparatedTokenizerTemplate<IsSVGWhitespace>
+    tokenizer(aValue, ',', nsCharSeparatedTokenizer::SEPARATOR_OPTIONAL);
+
+  nsCAutoString str1, str2;  // outside loop to minimize memory churn
+
+  while (tokenizer.hasMoreTokens()) {
+    CopyUTF16toUTF8(tokenizer.nextToken(), str1);
+    const char *token1 = str1.get();
+    if (*token1 == '\0' || !tokenizer.hasMoreTokens()) {
+      rv = NS_ERROR_DOM_SYNTAX_ERR;
+      break;
+    }
+    CopyUTF16toUTF8(tokenizer.nextToken(), str2);
+    const char *token2 = str2.get();
+    if (*token2 == '\0') {
+      rv = NS_ERROR_DOM_SYNTAX_ERR;
+      break;
+    }
+
+    char *end;
+    float x = float(PR_strtod(token1, &end));
+    if (*end != '\0' || !NS_FloatIsFinite(x)) {
+      rv = NS_ERROR_DOM_SYNTAX_ERR;
+      break;
+    }
+    float y = float(PR_strtod(token2, &end));
+    if (*end != '\0' || !NS_FloatIsFinite(y)) {
+      rv = NS_ERROR_DOM_SYNTAX_ERR;
+      break;
+    }
+
+    temp.AppendItem(SVGPoint(x, y));
+  }
+  if (tokenizer.lastTokenEndedWithSeparator()) {
+    rv = NS_ERROR_DOM_SYNTAX_ERR; // trailing comma
+  }
+  nsresult rv2 = CopyFrom(temp);
+  if (NS_FAILED(rv2)) {
+    return rv2; // prioritize OOM error code over syntax errors
+  }
+  return rv;
+}
new file mode 100644
--- /dev/null
+++ b/content/svg/content/src/SVGPointList.h
@@ -0,0 +1,230 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla SVG Project code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef MOZILLA_SVGPOINTLIST_H__
+#define MOZILLA_SVGPOINTLIST_H__
+
+#include "SVGPoint.h"
+#include "nsTArray.h"
+#include "nsSVGElement.h"
+
+namespace mozilla {
+
+/**
+ * ATTENTION! WARNING! WATCH OUT!!
+ *
+ * Consumers that modify objects of this type absolutely MUST keep the DOM
+ * wrappers for those lists (if any) in sync!! That's why this class is so
+ * locked down.
+ *
+ * The DOM wrapper class for this class is DOMSVGPointList.
+ */
+class SVGPointList
+{
+  friend class SVGAnimatedPointList;
+  friend class DOMSVGPointList;
+  friend class DOMSVGPoint;
+
+public:
+
+  SVGPointList(){}
+  ~SVGPointList(){}
+
+  // Only methods that don't make/permit modification to this list are public.
+  // Only our friend classes can access methods that may change us.
+
+  /// This may return an incomplete string on OOM, but that's acceptable.
+  void GetValueAsString(nsAString& aValue) const;
+
+  PRBool IsEmpty() const {
+    return mItems.IsEmpty();
+  }
+
+  PRUint32 Length() const {
+    return mItems.Length();
+  }
+
+  const SVGPoint& operator[](PRUint32 aIndex) const {
+    return mItems[aIndex];
+  }
+
+  PRBool operator==(const SVGPointList& rhs) const {
+    // memcmp can be faster than |mItems == rhs.mItems|
+    return mItems.Length() == rhs.mItems.Length() &&
+           memcmp(mItems.Elements(), rhs.mItems.Elements(),
+                  mItems.Length() * sizeof(SVGPoint)) == 0;
+  }
+
+  PRBool SetCapacity(PRUint32 aSize) {
+    return mItems.SetCapacity(aSize);
+  }
+
+  void Compact() {
+    mItems.Compact();
+  }
+
+  // Access to methods that can modify objects of this type is deliberately
+  // limited. This is to reduce the chances of someone modifying objects of
+  // this type without taking the necessary steps to keep DOM wrappers in sync.
+  // If you need wider access to these methods, consider adding a method to
+  // SVGAnimatedPointList and having that class act as an intermediary so it
+  // can take care of keeping DOM wrappers in sync.
+
+protected:
+
+  /**
+   * This may fail on OOM if the internal capacity needs to be increased, in
+   * which case the list will be left unmodified.
+   */
+  nsresult CopyFrom(const SVGPointList& rhs);
+
+  SVGPoint& operator[](PRUint32 aIndex) {
+    return mItems[aIndex];
+  }
+
+  /**
+   * This may fail (return PR_FALSE) on OOM if the internal capacity is being
+   * increased, in which case the list will be left unmodified.
+   */
+  PRBool SetLength(PRUint32 aNumberOfItems) {
+    return mItems.SetLength(aNumberOfItems);
+  }
+
+private:
+
+  // Marking the following private only serves to show which methods are only
+  // used by our friend classes (as opposed to our subclasses) - it doesn't
+  // really provide additional safety.
+
+  nsresult SetValueFromString(const nsAString& aValue);
+
+  void Clear() {
+    mItems.Clear();
+  }
+
+  PRBool InsertItem(PRUint32 aIndex, const SVGPoint &aPoint) {
+    if (aIndex >= mItems.Length()) {
+      aIndex = mItems.Length();
+    }
+    return !!mItems.InsertElementAt(aIndex, aPoint);
+  }
+
+  void ReplaceItem(PRUint32 aIndex, const SVGPoint &aPoint) {
+    NS_ASSERTION(aIndex < mItems.Length(),
+                 "DOM wrapper caller should have raised INDEX_SIZE_ERR");
+    mItems[aIndex] = aPoint;
+  }
+
+  void RemoveItem(PRUint32 aIndex) {
+    NS_ASSERTION(aIndex < mItems.Length(),
+                 "DOM wrapper caller should have raised INDEX_SIZE_ERR");
+    mItems.RemoveElementAt(aIndex);
+  }
+
+  PRBool AppendItem(SVGPoint aPoint) {
+    return !!mItems.AppendElement(aPoint);
+  }
+
+protected:
+
+  /* See SVGLengthList for the rationale for using nsTArray<SVGPoint> instead
+   * of nsTArray<SVGPoint, 1>.
+   */
+  nsTArray<SVGPoint> mItems;
+};
+
+
+/**
+ * This SVGPointList subclass is for SVGPointListSMILType which needs a
+ * mutable version of SVGPointList. Instances of this class do not have
+ * DOM wrappers that need to be kept in sync, so we can safely expose any
+ * protected base class methods required by the SMIL code.
+ *
+ * This class contains a strong reference to the element that instances of
+ * this class are being used to animate. This is because the SMIL code stores
+ * instances of this class in nsSMILValue objects, some of which are cached.
+ * Holding a strong reference to the element here prevents the element from
+ * disappearing out from under the SMIL code unexpectedly.
+ */
+class SVGPointListAndInfo : public SVGPointList
+{
+public:
+
+  SVGPointListAndInfo(nsSVGElement *aElement = nsnull)
+    : mElement(aElement)
+  {}
+
+  void SetInfo(nsSVGElement *aElement) {
+    mElement = aElement;
+  }
+
+  nsSVGElement* Element() const {
+    return mElement;
+  }
+
+  nsresult CopyFrom(const SVGPointListAndInfo& rhs) {
+    mElement = rhs.mElement;
+    return SVGPointList::CopyFrom(rhs);
+  }
+
+  /**
+   * Exposed so that SVGPointList baseVals can be copied to
+   * SVGPointListAndInfo objects. Note that callers should also call
+   * SetElement() when using this method!
+   */
+  nsresult CopyFrom(const SVGPointList& rhs) {
+    return SVGPointList::CopyFrom(rhs);
+  }
+  const SVGPoint& operator[](PRUint32 aIndex) const {
+    return SVGPointList::operator[](aIndex);
+  }
+  SVGPoint& operator[](PRUint32 aIndex) {
+    return SVGPointList::operator[](aIndex);
+  }
+  PRBool SetLength(PRUint32 aNumberOfItems) {
+    return SVGPointList::SetLength(aNumberOfItems);
+  }
+
+private:
+  // We must keep a strong reference to our element because we may belong to a
+  // cached baseVal nsSMILValue. See the comments starting at:
+  // https://bugzilla.mozilla.org/show_bug.cgi?id=515116#c15
+  nsRefPtr<nsSVGElement> mElement;
+};
+
+} // namespace mozilla
+
+#endif // MOZILLA_SVGPOINTLIST_H__
new file mode 100644
--- /dev/null
+++ b/content/svg/content/src/SVGPointListSMILType.cpp
@@ -0,0 +1,227 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Mozilla SVG project.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "SVGPointListSMILType.h"
+#include "nsSMILValue.h"
+#include "SVGPointList.h"
+#include "nsMathUtils.h"
+#include <math.h>
+
+using namespace mozilla;
+
+/*static*/ SVGPointListSMILType SVGPointListSMILType::sSingleton;
+
+//----------------------------------------------------------------------
+// nsISMILType implementation
+
+void
+SVGPointListSMILType::Init(nsSMILValue &aValue) const
+{
+  NS_ABORT_IF_FALSE(aValue.IsNull(), "Unexpected value type");
+
+  SVGPointListAndInfo* pointList = new SVGPointListAndInfo();
+
+  aValue.mU.mPtr = pointList;
+  aValue.mType = this;
+}
+
+void
+SVGPointListSMILType::Destroy(nsSMILValue& aValue) const
+{
+  NS_PRECONDITION(aValue.mType == this, "Unexpected SMIL value type");
+  delete static_cast<SVGPointListAndInfo*>(aValue.mU.mPtr);
+  aValue.mU.mPtr = nsnull;
+  aValue.mType = &nsSMILNullType::sSingleton;
+}
+
+nsresult
+SVGPointListSMILType::Assign(nsSMILValue& aDest,
+                              const nsSMILValue& aSrc) const
+{
+  NS_PRECONDITION(aDest.mType == aSrc.mType, "Incompatible SMIL types");
+  NS_PRECONDITION(aDest.mType == this, "Unexpected SMIL value");
+
+  const SVGPointListAndInfo* src =
+    static_cast<const SVGPointListAndInfo*>(aSrc.mU.mPtr);
+  SVGPointListAndInfo* dest =
+    static_cast<SVGPointListAndInfo*>(aDest.mU.mPtr);
+
+  return dest->CopyFrom(*src);
+}
+
+PRBool
+SVGPointListSMILType::IsEqual(const nsSMILValue& aLeft,
+                               const nsSMILValue& aRight) const
+{
+  NS_PRECONDITION(aLeft.mType == aRight.mType, "Incompatible SMIL types");
+  NS_PRECONDITION(aLeft.mType == this, "Unexpected type for SMIL value");
+
+  return *static_cast<const SVGPointListAndInfo*>(aLeft.mU.mPtr) ==
+         *static_cast<const SVGPointListAndInfo*>(aRight.mU.mPtr);
+}
+
+nsresult
+SVGPointListSMILType::Add(nsSMILValue& aDest,
+                          const nsSMILValue& aValueToAdd,
+                          PRUint32 aCount) const
+{
+  NS_PRECONDITION(aDest.mType == this, "Unexpected SMIL type");
+  NS_PRECONDITION(aValueToAdd.mType == this, "Incompatible SMIL type");
+
+  SVGPointListAndInfo& dest =
+    *static_cast<SVGPointListAndInfo*>(aDest.mU.mPtr);
+  const SVGPointListAndInfo& valueToAdd =
+    *static_cast<const SVGPointListAndInfo*>(aValueToAdd.mU.mPtr);
+
+  NS_ABORT_IF_FALSE(dest.Element() || valueToAdd.Element(),
+                    "Target element propagation failure");
+
+  if (!valueToAdd.Element()) {
+    NS_ABORT_IF_FALSE(valueToAdd.Length() == 0,
+                      "Not identity value - target element propagation failure");
+    return NS_OK;
+  }
+  if (!dest.Element()) {
+    NS_ABORT_IF_FALSE(dest.Length() == 0,
+                      "Not identity value - target element propagation failure");
+    if (!dest.SetLength(valueToAdd.Length())) {
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+    for (PRUint32 i = 0; i < dest.Length(); ++i) {
+      dest[i] = aCount * valueToAdd[i];
+    }
+    dest.SetInfo(valueToAdd.Element()); // propagate target element info!
+    return NS_OK;
+  }
+  NS_ABORT_IF_FALSE(dest.Element() == valueToAdd.Element(),
+                    "adding values from different elements...?");
+  if (dest.Length() != valueToAdd.Length()) {
+    // For now we only support animation between lists with the same number of
+    // items. nsSVGUtils::ReportToConsole
+    return NS_ERROR_FAILURE;
+  }
+  for (PRUint32 i = 0; i < dest.Length(); ++i) {
+    dest[i] += aCount * valueToAdd[i];
+  }
+  dest.SetInfo(valueToAdd.Element()); // propagate target element info!
+  return NS_OK;
+}
+
+nsresult
+SVGPointListSMILType::ComputeDistance(const nsSMILValue& aFrom,
+                                      const nsSMILValue& aTo,
+                                      double& aDistance) const
+{
+  NS_PRECONDITION(aFrom.mType == this, "Unexpected SMIL type");
+  NS_PRECONDITION(aTo.mType == this, "Incompatible SMIL type");
+
+  const SVGPointListAndInfo& from =
+    *static_cast<const SVGPointListAndInfo*>(aFrom.mU.mPtr);
+  const SVGPointListAndInfo& to =
+    *static_cast<const SVGPointListAndInfo*>(aTo.mU.mPtr);
+
+  if (from.Length() != to.Length()) {
+    // Lists in the 'values' attribute must have the same length.
+    // nsSVGUtils::ReportToConsole
+    return NS_ERROR_FAILURE;
+  }
+
+  // We return the root of the sum of the squares of the distances between the
+  // points at each corresponding index.
+
+  double total = 0.0;
+
+  for (PRUint32 i = 0; i < to.Length(); ++i) {
+    double dx = to[i].mX - from[i].mX;
+    double dy = to[i].mY - from[i].mY;
+    total += dx * dx + dy * dy;
+  }
+  double distance = sqrt(total);
+  if (!NS_FloatIsFinite(distance)) {
+    return NS_ERROR_FAILURE;
+  }
+  aDistance = distance;
+
+  return NS_OK;
+}
+
+nsresult
+SVGPointListSMILType::Interpolate(const nsSMILValue& aStartVal,
+                                  const nsSMILValue& aEndVal,
+                                  double aUnitDistance,
+                                  nsSMILValue& aResult) const
+{
+  NS_PRECONDITION(aStartVal.mType == aEndVal.mType,
+                  "Trying to interpolate different types");
+  NS_PRECONDITION(aStartVal.mType == this,
+                  "Unexpected types for interpolation");
+  NS_PRECONDITION(aResult.mType == this, "Unexpected result type");
+
+  const SVGPointListAndInfo& start =
+    *static_cast<const SVGPointListAndInfo*>(aStartVal.mU.mPtr);
+  const SVGPointListAndInfo& end =
+    *static_cast<const SVGPointListAndInfo*>(aEndVal.mU.mPtr);
+  SVGPointListAndInfo& result =
+    *static_cast<SVGPointListAndInfo*>(aResult.mU.mPtr);
+
+  NS_ABORT_IF_FALSE(end.Element(), "Can't propagate target element");
+  NS_ABORT_IF_FALSE(start.Element() == end.Element() || !start.Element(),
+                    "Different target elements");
+
+  if (start.Element() && // 'start' is not an "identity" value
+      start.Length() != end.Length()) {
+    // For now we only support animation between lists of the same length.
+    // nsSVGUtils::ReportToConsole
+    return NS_ERROR_FAILURE;
+  }
+  if (!result.SetLength(end.Length())) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  result.SetInfo(end.Element()); // propagate target element info!
+
+  if (start.Length() != end.Length()) {
+    NS_ABORT_IF_FALSE(start.Length() == 0, "Not an identity value");
+    for (PRUint32 i = 0; i < end.Length(); ++i) {
+      result[i] = aUnitDistance * end[i];
+    }
+    return NS_OK;
+  }
+  for (PRUint32 i = 0; i < end.Length(); ++i) {
+    result[i] = start[i] + (end[i] - start[i]) * aUnitDistance;
+  }
+  return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/content/svg/content/src/SVGPointListSMILType.h
@@ -0,0 +1,86 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Mozilla SVG project.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef MOZILLA_SVGPOINTLISTSMILTYPE_H_
+#define MOZILLA_SVGPOINTLISTSMILTYPE_H_
+
+#include "nsISMILType.h"
+
+class nsSMILValue;
+
+namespace mozilla {
+
+////////////////////////////////////////////////////////////////////////
+// SVGPointListSMILType
+//
+// Operations for animating an SVGPointList.
+//
+class SVGPointListSMILType : public nsISMILType
+{
+public:
+  // Singleton for nsSMILValue objects to hold onto.
+  static SVGPointListSMILType sSingleton;
+
+protected:
+  // nsISMILType Methods
+  // -------------------
+
+  virtual void     Init(nsSMILValue& aValue) const;
+
+  virtual void     Destroy(nsSMILValue& aValue) const;
+  virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const;
+  virtual PRBool   IsEqual(const nsSMILValue& aLeft,
+                           const nsSMILValue& aRight) const;
+  virtual nsresult Add(nsSMILValue& aDest, const nsSMILValue& aValueToAdd,
+                       PRUint32 aCount) const;
+  virtual nsresult ComputeDistance(const nsSMILValue& aFrom,
+                                   const nsSMILValue& aTo,
+                                   double& aDistance) const;
+  virtual nsresult Interpolate(const nsSMILValue& aStartVal,
+                               const nsSMILValue& aEndVal,
+                               double aUnitDistance,
+                               nsSMILValue& aResult) const;
+
+private:
+  // Private constructor & destructor: prevent instances beyond my singleton,
+  // and prevent others from deleting my singleton.
+  SVGPointListSMILType() {}
+  ~SVGPointListSMILType() {}
+};
+
+} // namespace mozilla
+
+#endif // MOZILLA_SVGPOINTLISTSMILTYPE_H_
--- a/content/svg/content/src/nsDOMSVGZoomEvent.cpp
+++ b/content/svg/content/src/nsDOMSVGZoomEvent.cpp
@@ -33,24 +33,25 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsDOMSVGZoomEvent.h"
 #include "nsContentUtils.h"
 #include "nsSVGRect.h"
-#include "nsSVGPoint.h"
+#include "DOMSVGPoint.h"
 #include "nsSVGSVGElement.h"
 #include "nsIDOMSVGSVGElement.h"
 #include "nsIContent.h"
 #include "nsIPresShell.h"
 #include "nsIDocument.h"
 #include "mozilla/dom/Element.h"
 
+using namespace mozilla;
 using namespace mozilla::dom;
 
 //----------------------------------------------------------------------
 // Implementation
 
 nsDOMSVGZoomEvent::nsDOMSVGZoomEvent(nsPresContext* aPresContext,
                                      nsGUIEvent* aEvent)
   : nsDOMUIEvent(aPresContext,
@@ -86,23 +87,25 @@ nsDOMSVGZoomEvent::nsDOMSVGZoomEvent(nsP
           nsSVGSVGElement *SVGSVGElement =
             static_cast<nsSVGSVGElement*>(rootElement);
   
           mNewScale = SVGSVGElement->GetCurrentScale();
           mPreviousScale = SVGSVGElement->GetPreviousScale();
 
           const nsSVGTranslatePoint& translate =
             SVGSVGElement->GetCurrentTranslate();
-          NS_NewSVGReadonlyPoint(getter_AddRefs(mNewTranslate),
-                                 translate.GetX(), translate.GetY());
+          mNewTranslate =
+            new DOMSVGPoint(translate.GetX(), translate.GetY());
+          mNewTranslate->SetReadonly(PR_TRUE);
 
           const nsSVGTranslatePoint& prevTranslate =
             SVGSVGElement->GetPreviousTranslate();
-          NS_NewSVGReadonlyPoint(getter_AddRefs(mPreviousTranslate),
-                                 prevTranslate.GetX(), prevTranslate.GetY());
+          mPreviousTranslate =
+            new DOMSVGPoint(prevTranslate.GetX(), prevTranslate.GetY());
+          mPreviousTranslate->SetReadonly(PR_TRUE);
         }
       }
     }
   }
 }
 
 
 //----------------------------------------------------------------------
--- a/content/svg/content/src/nsDOMSVGZoomEvent.h
+++ b/content/svg/content/src/nsDOMSVGZoomEvent.h
@@ -37,31 +37,37 @@
 
 #ifndef __NS_SVGZOOMEVENT_H__
 #define __NS_SVGZOOMEVENT_H__
 
 #include "nsIDOMSVGZoomEvent.h"
 #include "nsDOMUIEvent.h"
 #include "nsIDOMSVGSVGElement.h"
 
+namespace mozilla {
+class DOMSVGPoint;
+}
+
 class nsDOMSVGZoomEvent : public nsDOMUIEvent,
                           public nsIDOMSVGZoomEvent
 {
 public:
+  typedef mozilla::DOMSVGPoint DOMSVGPoint;
+
   nsDOMSVGZoomEvent(nsPresContext* aPresContext, nsGUIEvent* aEvent);
                      
   // nsISupports interface:
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIDOMSVGZoomEvent interface:
   NS_DECL_NSIDOMSVGZOOMEVENT
 
   // Forward to base class
   NS_FORWARD_TO_NSDOMUIEVENT
 
 private:
-  float                    mPreviousScale;
-  nsCOMPtr<nsIDOMSVGPoint> mPreviousTranslate;
-  float                    mNewScale;
-  nsCOMPtr<nsIDOMSVGPoint> mNewTranslate;
+  float mPreviousScale;
+  float mNewScale;
+  nsRefPtr<DOMSVGPoint> mPreviousTranslate;
+  nsRefPtr<DOMSVGPoint> mNewTranslate;
 };
 
 #endif // __NS_SVGZOOMEVENT_H__
--- a/content/svg/content/src/nsSVGElement.cpp
+++ b/content/svg/content/src/nsSVGElement.cpp
@@ -71,16 +71,17 @@
 #include "nsSVGInteger.h"
 #include "nsSVGAngle.h"
 #include "nsSVGBoolean.h"
 #include "nsSVGEnum.h"
 #include "nsSVGViewBox.h"
 #include "nsSVGString.h"
 #include "SVGAnimatedNumberList.h"
 #include "SVGAnimatedLengthList.h"
+#include "SVGAnimatedPointList.h"
 #include "SVGAnimatedPathSegList.h"
 #include "nsIDOMSVGUnitTypes.h"
 #include "nsIDOMSVGPointList.h"
 #include "nsIDOMSVGAnimatedPoints.h"
 #include "nsIDOMSVGTransformList.h"
 #include "nsIDOMSVGAnimTransformList.h"
 #include "nsIDOMSVGAnimatedRect.h"
 #include "nsIDOMSVGGradientElement.h"
@@ -180,17 +181,20 @@ nsSVGElement::Init()
   }
 
   NumberListAttributesInfo numberListInfo = GetNumberListInfo();
 
   for (i = 0; i < numberListInfo.mNumberListCount; i++) {
     numberListInfo.Reset(i);
   }
 
-  // No need to reset SVGPathData since the default value in always the same
+  // No need to reset SVGPointList since the default value is always the same
+  // (an empty list).
+
+  // No need to reset SVGPathData since the default value is always the same
   // (an empty list).
 
   StringAttributesInfo stringInfo = GetStringInfo();
 
   for (i = 0; i < stringInfo.mStringCount; i++) {
     stringInfo.Reset(i);
   }
 
@@ -394,16 +398,32 @@ nsSVGElement::ParseAttribute(PRInt32 aNa
           }
           foundMatch = PR_TRUE;
           break;
         }
       }
     }
 
     if (!foundMatch) {
+      // Check for SVGAnimatedPointList attribute
+      if (GetPointListAttrName() == aAttribute) {
+        SVGAnimatedPointList* pointList = GetAnimatedPointList();
+        if (pointList) {
+          rv = pointList->SetBaseValueString(aValue);
+          if (NS_FAILED(rv)) {
+            ReportAttributeParseFailure(GetOwnerDoc(), aAttribute, aValue);
+            // The spec says we parse everything up to the failure, so we don't
+            // call pointList->ClearBaseValue()
+          }
+          foundMatch = PR_TRUE;
+        }
+      }
+    }
+
+    if (!foundMatch) {
       // Check for SVGAnimatedPathSegList attribute
       if (GetPathDataAttrName() == aAttribute) {
         SVGAnimatedPathSegList* segList = GetAnimPathSegList();
         if (segList) {
           rv = segList->SetBaseValueString(aValue);
           if (NS_FAILED(rv)) {
             ReportAttributeParseFailure(GetOwnerDoc(), aAttribute, aValue);
             // The spec says we parse everything up to the failure, so we don't
@@ -619,16 +639,28 @@ nsSVGElement::UnsetAttr(PRInt32 aNamespa
           DidChangeNumberList(i, PR_FALSE);
           foundMatch = PR_TRUE;
           break;
         }
       }
     }
 
     if (!foundMatch) {
+      // Check if this is a point list attribute going away
+      if (GetPointListAttrName() == aName) {
+        SVGAnimatedPointList *pointList = GetAnimatedPointList();
+        if (pointList) {
+          pointList->ClearBaseValue();
+          DidChangePointList(PR_FALSE);
+          foundMatch = PR_TRUE;
+        }
+      }
+    }
+
+    if (!foundMatch) {
       // Check if this is a path segment list attribute going away
       if (GetPathDataAttrName() == aName) {
         SVGAnimatedPathSegList *segList = GetAnimPathSegList();
         if (segList) {
           segList->ClearBaseValue();
           DidChangePathSegList(PR_FALSE);
           foundMatch = PR_TRUE;
         }
@@ -1680,34 +1712,63 @@ nsSVGElement::GetAnimatedNumberList(nsIA
       return &info.mNumberLists[i];
     }
   }
   NS_ABORT_IF_FALSE(PR_FALSE, "Bad caller");
   return nsnull;
 }
 
 void
+nsSVGElement::DidChangePointList(PRBool aDoSetAttr)
+{
+  NS_ABORT_IF_FALSE(GetPointListAttrName(), "Changing non-existent point list?");
+
+  if (!aDoSetAttr)
+    return;
+
+  nsAutoString newStr;
+  GetAnimatedPointList()->GetBaseValue().GetValueAsString(newStr);
+
+  SetAttr(kNameSpaceID_None, GetPointListAttrName(), newStr, PR_TRUE);
+}
+
+void
+nsSVGElement::DidAnimatePointList()
+{
+  NS_ABORT_IF_FALSE(GetPointListAttrName(),
+                    "Animating non-existent path data?");
+
+  nsIFrame* frame = GetPrimaryFrame();
+
+  if (frame) {
+    frame->AttributeChanged(kNameSpaceID_None,
+                            GetPointListAttrName(),
+                            nsIDOMMutationEvent::MODIFICATION);
+  }
+}
+
+void
 nsSVGElement::DidChangePathSegList(PRBool aDoSetAttr)
 {
-  NS_ABORT_IF_FALSE(GetPathDataAttrName(), "Changing non-existant path data?");
+  NS_ABORT_IF_FALSE(GetPathDataAttrName(), "Changing non-existent path data?");
 
   if (!aDoSetAttr)
     return;
 
   nsAutoString newStr;
   GetAnimPathSegList()->GetBaseValue().GetValueAsString(newStr);
 
   SetAttr(kNameSpaceID_None, GetPathDataAttrName(), newStr, PR_TRUE);
 }
 
 void
 nsSVGElement::DidAnimatePathSegList()
 {
   NS_ABORT_IF_FALSE(GetPathDataAttrName(),
-                    "Animatinging non-existant path data?");
+                    "Animating non-existent path data?");
 
   nsIFrame* frame = GetPrimaryFrame();
 
   if (frame) {
     frame->AttributeChanged(kNameSpaceID_None,
                             GetPathDataAttrName(),
                             nsIDOMMutationEvent::MODIFICATION);
   }
@@ -2388,16 +2449,26 @@ nsSVGElement::GetAnimatedAttr(PRInt32 aN
     for (PRUint32 i = 0; i < info.mStringCount; i++) {
       if (aNamespaceID == info.mStringInfo[i].mNamespaceID &&
           aName == *info.mStringInfo[i].mName) {
         return info.mStrings[i].ToSMILAttr(this);
       }
     }
   }
 
+  // PointLists:
+  {
+    if (GetPointListAttrName() == aName) {
+      SVGAnimatedPointList *pointList = GetAnimatedPointList();
+      if (pointList) {
+        return pointList->ToSMILAttr(this);
+      }
+    }
+  }
+
   // PathSegLists:
   {
     if (GetPathDataAttrName() == aName) {
       SVGAnimatedPathSegList *segList = GetAnimPathSegList();
       if (segList) {
         return segList->ToSMILAttr(this);
       }
     }
--- a/content/svg/content/src/nsSVGElement.h
+++ b/content/svg/content/src/nsSVGElement.h
@@ -71,16 +71,17 @@ class nsSVGViewBox;
 class nsSVGPreserveAspectRatio;
 class nsSVGString;
 struct gfxMatrix;
 namespace mozilla {
 class SVGAnimatedNumberList;
 class SVGNumberList;
 class SVGAnimatedLengthList;
 class SVGUserUnitList;
+class SVGAnimatedPointList;
 class SVGAnimatedPathSegList;
 }
 
 typedef nsStyledElement nsSVGElementBase;
 
 class nsSVGElement : public nsSVGElementBase,    // nsIContent
                      public nsISVGValueObserver  // :nsISupportsWeakReference
 {
@@ -89,16 +90,17 @@ protected:
   nsresult Init();
   virtual ~nsSVGElement();
 
 public:
   typedef mozilla::SVGNumberList SVGNumberList;
   typedef mozilla::SVGAnimatedNumberList SVGAnimatedNumberList;
   typedef mozilla::SVGUserUnitList SVGUserUnitList;
   typedef mozilla::SVGAnimatedLengthList SVGAnimatedLengthList;
+  typedef mozilla::SVGAnimatedPointList SVGAnimatedPointList;
   typedef mozilla::SVGAnimatedPathSegList SVGAnimatedPathSegList;
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIContent interface methods
 
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
@@ -175,40 +177,45 @@ public:
   virtual void DidChangeInteger(PRUint8 aAttrEnum, PRBool aDoSetAttr);
   virtual void DidChangeAngle(PRUint8 aAttrEnum, PRBool aDoSetAttr);
   virtual void DidChangeBoolean(PRUint8 aAttrEnum, PRBool aDoSetAttr);
   virtual void DidChangeEnum(PRUint8 aAttrEnum, PRBool aDoSetAttr);
   virtual void DidChangeViewBox(PRBool aDoSetAttr);
   virtual void DidChangePreserveAspectRatio(PRBool aDoSetAttr);
   virtual void DidChangeNumberList(PRUint8 aAttrEnum, PRBool aDoSetAttr);
   virtual void DidChangeLengthList(PRUint8 aAttrEnum, PRBool aDoSetAttr);
+  virtual void DidChangePointList(PRBool aDoSetAttr);
   virtual void DidChangePathSegList(PRBool aDoSetAttr);
   virtual void DidChangeString(PRUint8 aAttrEnum) {}
 
   virtual void DidAnimateLength(PRUint8 aAttrEnum);
   virtual void DidAnimateNumber(PRUint8 aAttrEnum);
   virtual void DidAnimateInteger(PRUint8 aAttrEnum);
   virtual void DidAnimateAngle(PRUint8 aAttrEnum);
   virtual void DidAnimateBoolean(PRUint8 aAttrEnum);
   virtual void DidAnimateEnum(PRUint8 aAttrEnum);
   virtual void DidAnimateViewBox();
   virtual void DidAnimatePreserveAspectRatio();
   virtual void DidAnimateNumberList(PRUint8 aAttrEnum);
   virtual void DidAnimateLengthList(PRUint8 aAttrEnum);
+  virtual void DidAnimatePointList();
   virtual void DidAnimatePathSegList();
   virtual void DidAnimateTransform();
   virtual void DidAnimateString(PRUint8 aAttrEnum);
 
   void GetAnimatedLengthValues(float *aFirst, ...);
   void GetAnimatedNumberValues(float *aFirst, ...);
   void GetAnimatedIntegerValues(PRInt32 *aFirst, ...);
   SVGAnimatedNumberList* GetAnimatedNumberList(PRUint8 aAttrEnum);
   SVGAnimatedNumberList* GetAnimatedNumberList(nsIAtom *aAttrName);
   void GetAnimatedLengthListValues(SVGUserUnitList *aFirst, ...);
   SVGAnimatedLengthList* GetAnimatedLengthList(PRUint8 aAttrEnum);
+  virtual SVGAnimatedPointList* GetAnimatedPointList() {
+    return nsnull;
+  }
   virtual SVGAnimatedPathSegList* GetAnimPathSegList() {
     // DOM interface 'SVGAnimatedPathData' (*inherited* by nsSVGPathElement)
     // has a member called 'animatedPathSegList' member, so we have a shorter
     // name so we don't get hidden by the GetAnimatedPathSegList declared by
     // NS_DECL_NSIDOMSVGANIMATEDPATHDATA.
     return nsnull;
   }
 
@@ -221,16 +228,19 @@ public:
   void FlushAnimations() { /* do nothing */ }
 #endif
 
   virtual void RecompileScriptEventListeners();
 
   void GetStringBaseValue(PRUint8 aAttrEnum, nsAString& aResult) const;
   void SetStringBaseValue(PRUint8 aAttrEnum, const nsAString& aValue);
 
+  virtual nsIAtom* GetPointListAttrName() const {
+    return nsnull;
+  }
   virtual nsIAtom* GetPathDataAttrName() const {
     return nsnull;
   }
 
 protected:
   virtual nsresult AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
                                 const nsAString* aValue, PRBool aNotify);
   virtual PRBool ParseAttribute(PRInt32 aNamespaceID, nsIAtom* aAttribute,
--- a/content/svg/content/src/nsSVGPathElement.cpp
+++ b/content/svg/content/src/nsSVGPathElement.cpp
@@ -41,17 +41,17 @@
 #include "DOMSVGPathSeg.h"
 #include "DOMSVGPathSegList.h"
 #include "nsCOMPtr.h"
 #include "nsIFrame.h"
 #include "nsSVGPathDataParser.h"
 #include "nsSVGPathElement.h"
 #include "nsISVGValueUtils.h"
 #include "nsSVGUtils.h"
-#include "nsSVGPoint.h"
+#include "DOMSVGPoint.h"
 #include "gfxContext.h"
 #include "gfxPlatform.h"
 
 using namespace mozilla;
 
 nsSVGElement::NumberInfo nsSVGPathElement::sNumberInfo = 
 { &nsGkAtoms::pathLength, 0, PR_FALSE };
 
@@ -124,17 +124,18 @@ nsSVGPathElement::GetPointAtLength(float
   float totalLength = flat->GetLength();
   if (HasAttr(kNameSpaceID_None, nsGkAtoms::pathLength)) {
     float pathLength = mPathLength.GetAnimValue();
     distance *= totalLength / pathLength;
   }
   distance = NS_MAX(0.f,         distance);
   distance = NS_MIN(totalLength, distance);
 
-  return NS_NewSVGPoint(_retval, flat->FindPoint(gfxPoint(distance, 0)));
+  NS_ADDREF(*_retval = new DOMSVGPoint(flat->FindPoint(gfxPoint(distance, 0))));
+  return NS_OK;
 }
 
 /* unsigned long getPathSegAtLength (in float distance); */
 NS_IMETHODIMP
 nsSVGPathElement::GetPathSegAtLength(float distance, PRUint32 *_retval)
 {
   NS_ENSURE_FINITE(distance, NS_ERROR_ILLEGAL_VALUE);
   *_retval = mD.GetAnimValue().GetPathSegAtLength(distance);
deleted file mode 100644
--- a/content/svg/content/src/nsSVGPoint.cpp
+++ /dev/null
@@ -1,209 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is the Mozilla SVG project.
- *
- * The Initial Developer of the Original Code is
- * Crocodile Clips Ltd..
- * Portions created by the Initial Developer are Copyright (C) 2001
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Alex Fritze <alex.fritze@crocodile-clips.com> (original author)
- *   Jonathan Watt <jonathan.watt@strath.ac.uk>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "nsSVGPoint.h"
-#include "nsIDOMSVGMatrix.h"
-#include "nsSVGValue.h"
-#include "nsContentUtils.h"
-#include "nsDOMError.h"
-
-class nsSVGPoint : public nsIDOMSVGPoint,
-                   public nsSVGValue
-{
-public:
-  nsSVGPoint(float x, float y);
-
-  // nsISupports interface:
-  NS_DECL_ISUPPORTS
-
-  // nsIDOMSVGPoint interface:
-  NS_DECL_NSIDOMSVGPOINT
-
-  // nsISVGValue interface:
-  NS_IMETHOD SetValueString(const nsAString& aValue);
-  NS_IMETHOD GetValueString(nsAString& aValue);
-  
-protected:
-  float mX;
-  float mY;
-};
-
-
-//----------------------------------------------------------------------
-// Implementation
-
-nsresult
-NS_NewSVGPoint(nsIDOMSVGPoint** result, float x, float y)
-{
-  *result = new nsSVGPoint(x, y);
-  if (!*result)
-    return NS_ERROR_OUT_OF_MEMORY;
-  NS_ADDREF(*result);
-  return NS_OK;
-}
-
-nsresult
-NS_NewSVGPoint(nsIDOMSVGPoint** result, const gfxPoint& point)
-{
-  return NS_NewSVGPoint(result, float(point.x), float(point.y));
-}
-
-nsSVGPoint::nsSVGPoint(float x, float y)
-    : mX(x), mY(y)
-{
-}
-
-//----------------------------------------------------------------------
-// nsISupports methods:
-
-NS_IMPL_ADDREF(nsSVGPoint)
-NS_IMPL_RELEASE(nsSVGPoint)
-
-DOMCI_DATA(SVGPoint, nsSVGPoint)
-
-NS_INTERFACE_MAP_BEGIN(nsSVGPoint)
-  NS_INTERFACE_MAP_ENTRY(nsISVGValue)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMSVGPoint)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGPoint)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISVGValue)
-NS_INTERFACE_MAP_END
-
-//----------------------------------------------------------------------
-// nsIDOMSVGPoint methods:
-
-/* attribute float x; */
-NS_IMETHODIMP nsSVGPoint::GetX(float *aX)
-{
-  *aX = mX;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPoint::SetX(float aX)
-{
-  NS_ENSURE_FINITE(aX, NS_ERROR_ILLEGAL_VALUE);
-
-  WillModify();
-  mX = aX;
-  DidModify();
-  
-  return NS_OK;
-}
-
-/* attribute float y; */
-NS_IMETHODIMP nsSVGPoint::GetY(float *aY)
-{
-  *aY = mY;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPoint::SetY(float aY)
-{
-  NS_ENSURE_FINITE(aY, NS_ERROR_ILLEGAL_VALUE);
-
-  WillModify();
-  mY = aY;
-  DidModify();
-  
-  return NS_OK;
-}
-
-/* nsIDOMSVGPoint matrixTransform (in nsIDOMSVGMatrix matrix); */
-NS_IMETHODIMP nsSVGPoint::MatrixTransform(nsIDOMSVGMatrix *matrix,
-                                          nsIDOMSVGPoint **_retval)
-{
-  if (!matrix)
-    return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
-
-  float a, b, c, d, e, f;
-  matrix->GetA(&a);
-  matrix->GetB(&b);
-  matrix->GetC(&c);
-  matrix->GetD(&d);
-  matrix->GetE(&e);
-  matrix->GetF(&f);
-  
-  return NS_NewSVGPoint(_retval, a*mX + c*mY + e, b*mX + d*mY + f);
-}
-
-//----------------------------------------------------------------------
-// nsISVGValue methods:
-NS_IMETHODIMP
-nsSVGPoint::SetValueString(const nsAString& aValue)
-{
-  NS_NOTYETIMPLEMENTED("nsSVGPoint::SetValueString");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsSVGPoint::GetValueString(nsAString& aValue)
-{
-  NS_NOTYETIMPLEMENTED("nsSVGPoint::GetValueString");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-
-
-////////////////////////////////////////////////////////////////////////
-// Implement a readonly version of SVGPoint
-//
-// We need this because attributes of some SVG interfaces *and* the objects the
-// attributes refer to (including SVGPoints) are supposed to be readonly
-
-class nsSVGReadonlyPoint : public nsSVGPoint
-{
-public:
-  nsSVGReadonlyPoint(float x, float y)
-    : nsSVGPoint(x, y)
-  {
-  }
-
-  // override setters to make the whole object readonly
-  NS_IMETHODIMP SetX(float) { return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; }
-  NS_IMETHODIMP SetY(float) { return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; }
-  NS_IMETHODIMP SetValueString(const nsAString&) { return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; }
-};
-
-nsresult
-NS_NewSVGReadonlyPoint(nsIDOMSVGPoint** result, float x, float y)
-{
-  *result = new nsSVGReadonlyPoint(x, y);
-  if (!*result)
-    return NS_ERROR_OUT_OF_MEMORY;
-  NS_ADDREF(*result);
-  return NS_OK;
-}
-
deleted file mode 100644
--- a/content/svg/content/src/nsSVGPoint.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is the Mozilla SVG project.
- *
- * The Initial Developer of the Original Code is
- * Crocodile Clips Ltd..
- * Portions created by the Initial Developer are Copyright (C) 2001
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Alex Fritze <alex.fritze@crocodile-clips.com> (original author)
- *   Jonathan Watt <jonathan.watt@strath.ac.uk>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef __NS_SVGPOINT_H__
-#define __NS_SVGPOINT_H__
-
-#include "nsIDOMSVGPoint.h"
-#include "gfxPoint.h"
-
-nsresult
-NS_NewSVGPoint(nsIDOMSVGPoint** result, float x = 0.0f, float y = 0.0f);
-
-nsresult
-NS_NewSVGPoint(nsIDOMSVGPoint** result, const gfxPoint& point);
-
-nsresult
-NS_NewSVGReadonlyPoint(nsIDOMSVGPoint** result, float x = 0.0f, float y = 0.0f);
-
-#endif //__NS_SVGPOINT_H__
deleted file mode 100644
--- a/content/svg/content/src/nsSVGPointList.cpp
+++ /dev/null
@@ -1,377 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is the Mozilla SVG project.
- *
- * The Initial Developer of the Original Code is
- * Crocodile Clips Ltd..
- * Portions created by the Initial Developer are Copyright (C) 2001
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Alex Fritze <alex.fritze@crocodile-clips.com> (original author)
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "nsSVGPointList.h"
-#include "nsSVGPoint.h"
-#include "nsSVGUtils.h"
-#include "nsCharSeparatedTokenizer.h"
-#include "nsDOMError.h"
-#include "prdtoa.h"
-#include "nsReadableUtils.h"
-#include "nsTextFormatter.h"
-#include "nsCRT.h"
-#include "nsCOMArray.h"
-#include "nsContentUtils.h"
-
-#define NS_ENSURE_NATIVE_POINT(obj, retval)             \
-  {                                                     \
-    nsCOMPtr<nsISVGValue> val = do_QueryInterface(obj); \
-    if (!val) {                                         \
-      *retval = nsnull;                                 \
-      return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;           \
-    }                                                   \
-  }
-
-nsresult
-nsSVGPointList::Create(const nsAString& aValue,
-                       nsISVGValue** aResult)
-{
-  *aResult = (nsISVGValue*) new nsSVGPointList();
-  if(!*aResult) return NS_ERROR_OUT_OF_MEMORY;
-  
-  NS_ADDREF(*aResult);
-
-  (*aResult)->SetValueString(aValue);  
-  return NS_OK;
-}
-
-nsresult
-nsSVGPointList::Create(nsIDOMSVGPointList** aResult)
-{
-  *aResult = (nsIDOMSVGPointList*) new nsSVGPointList();
-  if(!*aResult) return NS_ERROR_OUT_OF_MEMORY;
-  
-  NS_ADDREF(*aResult);
-  return NS_OK;
-}
-
-nsSVGPointList::nsSVGPointList()
-{
-}
-
-nsSVGPointList::~nsSVGPointList()
-{
-  ReleasePoints();
-}
-
-void
-nsSVGPointList::ReleasePoints()
-{
-  WillModify();
-  PRUint32 count = mPoints.Length();
-  for (PRUint32 i = 0; i < count; ++i) {
-    nsIDOMSVGPoint* point = ElementAt(i);
-    nsCOMPtr<nsISVGValue> val = do_QueryInterface(point);
-    if (val)
-      val->RemoveObserver(this);
-    NS_RELEASE(point);
-  }
-  mPoints.Clear();
-  DidModify();
-}
-
-nsIDOMSVGPoint*
-nsSVGPointList::ElementAt(PRInt32 index)
-{
-  return mPoints.ElementAt(index);
-}
-
-void
-nsSVGPointList::AppendElement(nsIDOMSVGPoint* aElement)
-{
-  WillModify();
-  NS_ADDREF(aElement);
-  mPoints.AppendElement(aElement);
-  nsCOMPtr<nsISVGValue> val = do_QueryInterface(aElement);
-  if (val)
-    val->AddObserver(this);
-  DidModify();
-}
-
-void
-nsSVGPointList::RemoveElementAt(PRInt32 index)
-{
-  WillModify();
-  nsIDOMSVGPoint* point = ElementAt(index);
-  NS_ASSERTION(point, "null point");
-  nsCOMPtr<nsISVGValue> val = do_QueryInterface(point);
-  if (val)
-    val->RemoveObserver(this);
-  mPoints.RemoveElementAt(index);
-  NS_RELEASE(point);
-  DidModify();
-}
-
-void
-nsSVGPointList::InsertElementAt(nsIDOMSVGPoint* aElement, PRInt32 index)
-{
-  WillModify();
-  NS_ADDREF(aElement);
-  mPoints.InsertElementAt(index, aElement);
-  nsCOMPtr<nsISVGValue> val = do_QueryInterface(aElement);
-  if (val)
-    val->AddObserver(this);
-  DidModify();
-}
-
-//----------------------------------------------------------------------
-// nsISupports methods:
-
-NS_IMPL_ADDREF(nsSVGPointList)
-NS_IMPL_RELEASE(nsSVGPointList)
-
-DOMCI_DATA(SVGPointList, nsSVGPointList)
-
-NS_INTERFACE_MAP_BEGIN(nsSVGPointList)
-  NS_INTERFACE_MAP_ENTRY(nsISVGValue)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMSVGPointList)
-  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
-  NS_INTERFACE_MAP_ENTRY(nsISVGValueObserver)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGPointList)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISVGValue)
-NS_INTERFACE_MAP_END
-
-
-//----------------------------------------------------------------------
-// nsISVGValue methods:
-
-NS_IMETHODIMP
-nsSVGPointList::SetValueString(const nsAString& aValue)
-{
-  nsCharSeparatedTokenizer
-    tokenizer(aValue, ',',
-              nsCharSeparatedTokenizer::SEPARATOR_OPTIONAL);
-  nsCOMArray<nsIDOMSVGPoint> points;
-
-  PRBool parseError = PR_FALSE;
-
-  while (tokenizer.hasMoreTokens()) {
-    // Parse 2 tokens
-    NS_ConvertUTF16toUTF8 utf8String1(tokenizer.nextToken());
-    const char *token1 = utf8String1.get();
-    if (!tokenizer.hasMoreTokens() ||  // No 2nd token.
-        *token1 == '\0') {             // 1st token is empty string.
-      parseError = PR_TRUE;
-      break;
-    }
-    NS_ConvertUTF16toUTF8 utf8String2(tokenizer.nextToken());
-    const char *token2 = utf8String2.get();
-    if (*token2 == '\0') {             // 2nd token is empty string.
-      parseError = PR_TRUE;
-      break;
-    }
-
-    // Convert parsed tokens to float values.
-    char *end;
-    float x = float(PR_strtod(token1, &end));
-    if (*end != '\0' || !NS_FloatIsFinite(x)) {
-      parseError = PR_TRUE;
-      break;
-    }
-    float y = float(PR_strtod(token2, &end));
-    if (*end != '\0' || !NS_FloatIsFinite(y)) {
-      parseError = PR_TRUE;
-      break;
-    }
-
-    // Build a point from our parsed float values.
-    nsCOMPtr<nsIDOMSVGPoint> point;
-    NS_NewSVGPoint(getter_AddRefs(point), x, y); // uses infallible 'new'.
-    points.AppendObject(point);
-  }
-
-  if (tokenizer.lastTokenEndedWithSeparator()) { // Reject trailing comma
-    parseError = PR_TRUE;
-  }
-
-  if (parseError) {
-    // XXX nsSVGUtils::ReportToConsole()
-  }
-
-  WillModify();
-  ReleasePoints();
-  PRInt32 count = points.Count();
-  for (PRInt32 i = 0; i < count; ++i) {
-    AppendElement(points.ObjectAt(i));
-  }
-  DidModify();
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSVGPointList::GetValueString(nsAString& aValue)
-{
-  aValue.Truncate();
-
-  PRUint32 count = mPoints.Length();
-
-  if (count == 0) return NS_OK;
-
-  PRUint32 i = 0;
-  PRUnichar buf[48];
-  
-  while (1) {
-    nsIDOMSVGPoint* point = ElementAt(i);
-    float x, y;
-    point->GetX(&x);
-    point->GetY(&y);
-    
-    nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar), NS_LITERAL_STRING("%g,%g").get(), (double)x, (double)y);
-    aValue.Append(buf);
-
-    if (++i >= count) break;
-
-    aValue.AppendLiteral(" ");
-  }
-  
-  return NS_OK;
-}
-
-//----------------------------------------------------------------------
-// nsIDOMSVGPointList methods:
-
-/* readonly attribute unsigned long numberOfItems; */
-NS_IMETHODIMP nsSVGPointList::GetNumberOfItems(PRUint32 *aNumberOfItems)
-{
-  *aNumberOfItems = mPoints.Length();
-  return NS_OK;
-}
-
-/* void clear (); */
-NS_IMETHODIMP nsSVGPointList::Clear()
-{
-  WillModify();
-  ReleasePoints();
-  DidModify();
-  return NS_OK;
-}
-
-/* nsIDOMSVGPoint initialize (in nsIDOMSVGPoint newItem); */
-NS_IMETHODIMP nsSVGPointList::Initialize(nsIDOMSVGPoint *newItem,
-                                         nsIDOMSVGPoint **_retval)
-{
-  NS_ENSURE_NATIVE_POINT(newItem, _retval);
-  Clear();
-  return AppendItem(newItem, _retval);
-}
-
-/* nsIDOMSVGPoint getItem (in unsigned long index); */
-NS_IMETHODIMP nsSVGPointList::GetItem(PRUint32 index, nsIDOMSVGPoint **_retval)
-{
-  if (index >= mPoints.Length()) {
-    *_retval = nsnull;
-    return NS_ERROR_DOM_INDEX_SIZE_ERR;
-  }
-
-  *_retval  = ElementAt(index);
-  NS_ADDREF(*_retval);
-  return NS_OK;
-}
-
-/* nsIDOMSVGPoint insertItemBefore (in nsIDOMSVGPoint newItem, in unsigned long index); */
-NS_IMETHODIMP nsSVGPointList::InsertItemBefore(nsIDOMSVGPoint *newItem,
-                                               PRUint32 index,
-                                               nsIDOMSVGPoint **_retval)
-{
-  NS_ENSURE_NATIVE_POINT(newItem, _retval);
-
-  NS_NOTYETIMPLEMENTED("write me");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-/* nsIDOMSVGPoint replaceItem (in nsIDOMSVGPoint newItem, in unsigned long index); */
-NS_IMETHODIMP nsSVGPointList::ReplaceItem(nsIDOMSVGPoint *newItem,
-                                          PRUint32 index,
-                                          nsIDOMSVGPoint **_retval)
-{
-  NS_ENSURE_NATIVE_POINT(newItem, _retval);
-
-  NS_NOTYETIMPLEMENTED("write me");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-/* nsIDOMSVGPoint removeItem (in unsigned long index); */
-NS_IMETHODIMP nsSVGPointList::RemoveItem(PRUint32 index, nsIDOMSVGPoint **_retval)
-{
-  if (index >= mPoints.Length()) {
-    *_retval = nsnull;
-    return NS_ERROR_DOM_INDEX_SIZE_ERR;
-  }
-
-  *_retval = ElementAt(index);
-  NS_ADDREF(*_retval);
-  WillModify();
-  RemoveElementAt(index);
-  DidModify();
-  return NS_OK;
-}
-
-/* nsIDOMSVGPoint appendItem (in nsIDOMSVGPoint newItem); */
-NS_IMETHODIMP nsSVGPointList::AppendItem(nsIDOMSVGPoint *newItem,
-                                         nsIDOMSVGPoint **_retval)
-{
-  // XXX The SVG specs state that 'if newItem is already in a list, it
-  // is removed from its previous list before it is inserted into this
-  // list'. We don't do that. Should we?
-  
-  NS_ENSURE_NATIVE_POINT(newItem, _retval);
-  *_retval = newItem;
-  AppendElement(newItem);
-  NS_ADDREF(*_retval);
-  return NS_OK;
-}
-
-//----------------------------------------------------------------------
-// nsISVGValueObserver methods
-
-NS_IMETHODIMP
-nsSVGPointList::WillModifySVGObservable(nsISVGValue* observable,
-                                        modificationType aModType)
-{
-  WillModify(aModType);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSVGPointList::DidModifySVGObservable (nsISVGValue* observable,
-                                        modificationType aModType)
-{
-  DidModify(aModType);
-  return NS_OK;
-}
deleted file mode 100644
--- a/content/svg/content/src/nsSVGPointList.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is the Mozilla SVG project.
- *
- * The Initial Developer of the Original Code is
- * Crocodile Clips Ltd..
- * Portions created by the Initial Developer are Copyright (C) 2001
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Alex Fritze <alex.fritze@crocodile-clips.com> (original author)
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef __NS_SVGPOINTLIST_H__
-#define __NS_SVGPOINTLIST_H__
-
-#include "nsSVGValue.h"
-#include "nsISVGValueObserver.h"
-#include "nsWeakReference.h"
-#include "nsIDOMSVGPointList.h"
-#include "nsTArray.h"
-
-
-class nsSVGPointList : public nsSVGValue,
-                       public nsIDOMSVGPointList,
-                       public nsISVGValueObserver
-{
-public:
-  static nsresult Create(const nsAString& aValue, nsISVGValue** aResult);
-  static nsresult Create(nsIDOMSVGPointList** aResult);
-  
-protected:
-  nsSVGPointList();
-  virtual ~nsSVGPointList();
-  
-public:
-  // nsISupports interface:
-  NS_DECL_ISUPPORTS
-
-  // nsIDOMSVGPointList interface:
-  NS_DECL_NSIDOMSVGPOINTLIST
-  
-  // remainder of nsISVGValue interface:
-  NS_IMETHOD SetValueString(const nsAString& aValue);
-  NS_IMETHOD GetValueString(nsAString& aValue);
-
-  // nsISVGValueObserver
-  NS_IMETHOD WillModifySVGObservable(nsISVGValue* observable,
-                                     modificationType aModType);
-  NS_IMETHOD DidModifySVGObservable (nsISVGValue* observable,
-                                     modificationType aModType);
-  
-  // nsISupportsWeakReference
-  // implementation inherited from nsSupportsWeakReference
-
-  
-  // other methods:
-  nsIDOMSVGPoint* ElementAt(PRInt32 index);
-  void AppendElement(nsIDOMSVGPoint* aElement);
-  void RemoveElementAt(PRInt32 index);
-  void InsertElementAt(nsIDOMSVGPoint* aElement, PRInt32 index);
-  
-protected:
-  void ReleasePoints();
-  
-  nsAutoTArray<nsIDOMSVGPoint*, 8> mPoints;
-};
-
-
-#endif //__NS_SVGPOINTLIST_H__
--- a/content/svg/content/src/nsSVGPolyElement.cpp
+++ b/content/svg/content/src/nsSVGPolyElement.cpp
@@ -30,17 +30,21 @@
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsSVGPolyElement.h"
+#include "DOMSVGPointList.h"
 #include "gfxContext.h"
+#include "nsSVGUtils.h"
+
+using namespace mozilla;
 
 //----------------------------------------------------------------------
 // nsISupports methods
 
 NS_IMPL_ADDREF_INHERITED(nsSVGPolyElement,nsSVGPolyElementBase)
 NS_IMPL_RELEASE_INHERITED(nsSVGPolyElement,nsSVGPolyElementBase)
 
 NS_INTERFACE_MAP_BEGIN(nsSVGPolyElement)
@@ -51,51 +55,34 @@ NS_INTERFACE_MAP_END_INHERITING(nsSVGPol
 // Implementation
 
 nsSVGPolyElement::nsSVGPolyElement(already_AddRefed<nsINodeInfo> aNodeInfo)
   : nsSVGPolyElementBase(aNodeInfo)
 {
 
 }
 
-nsresult
-nsSVGPolyElement::Init()
-{
-  nsresult rv = nsSVGPolyElementBase::Init();
-  NS_ENSURE_SUCCESS(rv,rv);
-
-  // Create mapped properties:
-  
-  // points #IMPLIED
-  rv = nsSVGPointList::Create(getter_AddRefs(mPoints));
-  NS_ENSURE_SUCCESS(rv,rv);
-  rv = AddMappedSVGValue(nsGkAtoms::points, mPoints);
-  NS_ENSURE_SUCCESS(rv,rv);
-
-  return rv;
-}
-
 //----------------------------------------------------------------------
 // nsIDOMSGAnimatedPoints methods:
 
 /* readonly attribute nsIDOMSVGPointList points; */
 NS_IMETHODIMP 
 nsSVGPolyElement::GetPoints(nsIDOMSVGPointList * *aPoints)
 {
-  *aPoints = mPoints;
-  NS_ADDREF(*aPoints);
+  void *key = mPoints.GetBaseValKey();
+  *aPoints = DOMSVGPointList::GetDOMWrapper(key, this, PR_FALSE).get();
   return NS_OK;
 }
 
 /* readonly attribute nsIDOMSVGPointList animatedPoints; */
 NS_IMETHODIMP 
 nsSVGPolyElement::GetAnimatedPoints(nsIDOMSVGPointList * *aAnimatedPoints)
 {
-  *aAnimatedPoints = mPoints;
-  NS_ADDREF(*aAnimatedPoints);
+  void *key = mPoints.GetAnimValKey();
+  *aAnimatedPoints = DOMSVGPointList::GetDOMWrapper(key, this, PR_TRUE).get();
   return NS_OK;
 }
 
 //----------------------------------------------------------------------
 // nsIContent methods
 
 NS_IMETHODIMP_(PRBool)
 nsSVGPolyElement::IsAttributeMapped(const nsIAtom* name) const
@@ -118,34 +105,26 @@ nsSVGPolyElement::AttributeDefinesGeomet
     return PR_TRUE;
 
   return PR_FALSE;
 }
 
 void
 nsSVGPolyElement::GetMarkPoints(nsTArray<nsSVGMark> *aMarks)
 {
-  if (!mPoints)
-    return;
+  const SVGPointList &points = mPoints.GetAnimValue();
 
-  PRUint32 count;
-  mPoints->GetNumberOfItems(&count);
-  if (count == 0)
+  if (!points.Length())
     return;
 
   float px = 0.0, py = 0.0, prevAngle;
 
-  for (PRUint32 i = 0; i < count; ++i) {
-    nsCOMPtr<nsIDOMSVGPoint> point;
-    mPoints->GetItem(i, getter_AddRefs(point));
-
-    float x, y;
-    point->GetX(&x);
-    point->GetY(&y);
-
+  for (PRUint32 i = 0; i < points.Length(); ++i) {
+    float x = points[i].mX;
+    float y = points[i].mY;
     float angle = atan2(y-py, x-px);
     if (i == 1)
       aMarks->ElementAt(aMarks->Length() - 1).angle = angle;
     else if (i > 1)
       aMarks->ElementAt(aMarks->Length() - 1).angle =
         nsSVGUtils::AngleBisect(prevAngle, angle);
 
     aMarks->AppendElement(nsSVGMark(x, y, 0));
@@ -156,31 +135,19 @@ nsSVGPolyElement::GetMarkPoints(nsTArray
   }
 
   aMarks->ElementAt(aMarks->Length() - 1).angle = prevAngle;
 }
 
 void
 nsSVGPolyElement::ConstructPath(gfxContext *aCtx)
 {
-  if (!mPoints)
-    return;
+  const SVGPointList &points = mPoints.GetAnimValue();
 
-  PRUint32 count;
-  mPoints->GetNumberOfItems(&count);
-  if (count == 0)
+  if (!points.Length())
     return;
 
-  PRUint32 i;
-  for (i = 0; i < count; ++i) {
-    nsCOMPtr<nsIDOMSVGPoint> point;
-    mPoints->GetItem(i, getter_AddRefs(point));
-
-    float x, y;
-    point->GetX(&x);
-    point->GetY(&y);
-    if (i == 0)
-      aCtx->MoveTo(gfxPoint(x, y));
-    else
-      aCtx->LineTo(gfxPoint(x, y));
+  aCtx->MoveTo(points[0]);
+  for (PRUint32 i = 1; i < points.Length(); ++i) {
+    aCtx->LineTo(points[i]);
   }
 }
 
--- a/content/svg/content/src/nsSVGPolyElement.h
+++ b/content/svg/content/src/nsSVGPolyElement.h
@@ -33,46 +33,48 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef NS_SVGPOLYELEMENT_H_
 #define NS_SVGPOLYELEMENT_H_
 
 #include "nsSVGPathGeometryElement.h"
-#include "nsCOMPtr.h"
-#include "nsIDOMSVGPoint.h"
-#include "nsSVGPointList.h"
 #include "nsIDOMSVGAnimatedPoints.h"
-#include "nsSVGUtils.h"
+#include "SVGAnimatedPointList.h"
 
 typedef nsSVGPathGeometryElement nsSVGPolyElementBase;
 
 class gfxContext;
 
 class nsSVGPolyElement : public nsSVGPolyElementBase,
                          public nsIDOMSVGAnimatedPoints
 {
 protected:
   nsSVGPolyElement(already_AddRefed<nsINodeInfo> aNodeInfo);
-  nsresult Init();
 
 public:
   //interfaces
   
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIDOMSVGANIMATEDPOINTS
 
   // nsIContent interface
   NS_IMETHOD_(PRBool) IsAttributeMapped(const nsIAtom* name) const;
-  
+
+  virtual SVGAnimatedPointList* GetAnimatedPointList() {
+    return &mPoints;
+  }
+  virtual nsIAtom* GetPointListAttrName() const {
+    return nsGkAtoms::points;
+  }
+
   // nsSVGPathGeometryElement methods:
   virtual PRBool AttributeDefinesGeometry(const nsIAtom *aName);
   virtual PRBool IsMarkable() { return PR_TRUE; }
   virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks);
   virtual void ConstructPath(gfxContext *aCtx);
 
 protected:
-  nsCOMPtr<nsIDOMSVGPointList> mPoints;
-
+  SVGAnimatedPointList mPoints;
 };
 
 #endif //NS_SVGPOLYELEMENT_H_
--- a/content/svg/content/src/nsSVGPolygonElement.cpp
+++ b/content/svg/content/src/nsSVGPolygonElement.cpp
@@ -34,16 +34,17 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsSVGPolyElement.h"
 #include "nsIDOMSVGPolygonElement.h"
 #include "gfxContext.h"
+#include "nsSVGUtils.h"
 
 typedef nsSVGPolyElement nsSVGPolygonElementBase;
 
 class nsSVGPolygonElement : public nsSVGPolygonElementBase,
                             public nsIDOMSVGPolygonElement
 {
 protected:
   friend nsresult NS_NewSVGPolygonElement(nsIContent **aResult,
--- a/content/svg/content/src/nsSVGSVGElement.cpp
+++ b/content/svg/content/src/nsSVGSVGElement.cpp
@@ -43,17 +43,17 @@
 #include "DOMSVGLength.h"
 #include "nsSVGAngle.h"
 #include "nsCOMPtr.h"
 #include "nsIPresShell.h"
 #include "nsContentUtils.h"
 #include "nsIDocument.h"
 #include "nsPresContext.h"
 #include "nsSVGMatrix.h"
-#include "nsSVGPoint.h"
+#include "DOMSVGPoint.h"
 #include "nsSVGTransform.h"
 #include "nsIDOMEventTarget.h"
 #include "nsIFrame.h"
 #include "nsISVGSVGFrame.h" //XXX
 #include "nsSVGRect.h"
 #include "nsISVGValueUtils.h"
 #include "nsDOMError.h"
 #include "nsISVGChildFrame.h"
@@ -125,18 +125,19 @@ nsSVGTranslatePoint::DOMVal::MatrixTrans
   matrix->GetB(&b);
   matrix->GetC(&c);
   matrix->GetD(&d);
   matrix->GetE(&e);
   matrix->GetF(&f);
 
   float x = mVal->GetX();
   float y = mVal->GetY();
-  
-  return NS_NewSVGPoint(_retval, a*x + c*y + e, b*x + d*y + f);
+
+  NS_ADDREF(*_retval = new DOMSVGPoint(a*x + c*y + e, b*x + d*y + f));
+  return NS_OK;
 }
 
 nsSVGElement::LengthInfo nsSVGSVGElement::sLengthInfo[4] =
 {
   { &nsGkAtoms::x, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, nsSVGUtils::X },
   { &nsGkAtoms::y, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, nsSVGUtils::Y },
   { &nsGkAtoms::width, 100, nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE, nsSVGUtils::X },
   { &nsGkAtoms::height, 100, nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE, nsSVGUtils::Y },
@@ -650,17 +651,18 @@ nsSVGSVGElement::CreateSVGAngle(nsIDOMSV
 {
   return NS_NewDOMSVGAngle(_retval);
 }
 
 /* nsIDOMSVGPoint createSVGPoint (); */
 NS_IMETHODIMP
 nsSVGSVGElement::CreateSVGPoint(nsIDOMSVGPoint **_retval)
 {
-  return NS_NewSVGPoint(_retval);
+  NS_ADDREF(*_retval = new DOMSVGPoint(0, 0));
+  return NS_OK;
 }
 
 /* nsIDOMSVGMatrix createSVGMatrix (); */
 NS_IMETHODIMP
 nsSVGSVGElement::CreateSVGMatrix(nsIDOMSVGMatrix **_retval)
 {
   return NS_NewSVGMatrix(_retval);
 }
--- a/content/svg/content/test/test_SVGxxxList.xhtml
+++ b/content/svg/content/test/test_SVGxxxList.xhtml
@@ -17,16 +17,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     <filter>
       <feComponentTransfer>
         <feFuncR id="feFuncR" type="table"/>
       </feComponentTransfer>
     </filter>
   </desc>
   <text id="text">text</text>
   <path id="path"/>
+  <polyline id="polyline"/>
 </svg>
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 <![CDATA[
 
 
 SimpleTest.waitForExplicitFinish();
@@ -142,36 +143,37 @@ var tests = [
     attr_val_5a: '3 4 5 6 7',
     attr_val_5b: '7 6 5 4 3',
     item_constructor: function() {
       // We need this function literal to avoid "Illegal operation on
       // WrappedNative prototype object" NS_ERROR_XPC_BAD_OP_ON_WN_PROTO.
       return document.getElementById('svg').createSVGNumber();
     }
   },
-/*
   {
     // SVGPointList test:
     target_element_id: 'polyline',
     attr_name: 'points',
     prop_name: null, // SVGAnimatedPoints is an inherited interface!
     bv_name: 'points',
     av_name: 'animatedPoints',
     el_type: 'SVGPolylineElement',
     prop_type: null,
     list_type: 'SVGPointList',
     item_type: 'SVGPoint',
-    attr_val_3a: '',
-    attr_val_3b: '',
-    attr_val_4 : '',
-    attr_val_5a: '',
-    attr_val_5b: '',
-    item_constructor: document.getElementById('svg').createSVGPoint
+    attr_val_3a: ' 10,10 50,50 90,10 ',
+    attr_val_3b: ' 10,50 50,10 90,50 ',
+    attr_val_4 : ' 10,10 50,50 90,10 200,100 ',
+    attr_val_5a: ' 10,10 50,50 90,10 130,50 170,10 ',
+    attr_val_5b: ' 50,10 50,10 90,50 130,10 170,50 ',
+    item_constructor: function() {
+      // XXX return different values each time
+      return document.getElementById('svg').createSVGPoint();
+    }
   },
-*/
   {
     // SVGPathSegList test:
     target_element_id: 'path',
     attr_name: 'd',
     prop_name: null, // SVGAnimatedPathData is an inherited interface!
     bv_name: 'pathSegList',
     av_name: 'animatedPathSegList',
     el_type: 'SVGPathElement',
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/smil/anim-polygon-points-01-ref.svg
@@ -0,0 +1,17 @@
+<svg xmlns="http://www.w3.org/2000/svg">
+  <style type="text/css">
+    polygon { fill: blue; }
+  </style>
+
+  <polygon points="10,10 70,50 110,10 160,30 210,10"/>
+
+  <polygon transform="translate(0, 70)"
+           points="10,10 70,50 110,10 160,30 210,10"/>
+
+  <polygon transform="translate(0, 140)"
+           points="10,10 70,50 110,10 160,30 210,10"/>
+
+  <polygon transform="translate(0, 210)"
+           points="10,10 70,10 110,10 160,70 210,10"/>
+
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/smil/anim-polygon-points-01.svg
@@ -0,0 +1,73 @@
+<!--
+  From https://bugzilla.mozilla.org/show_bug.cgi?id=522308
+-->
+<svg xmlns="http://www.w3.org/2000/svg"
+     xmlns:xlink="http://www.w3.org/1999/xlink"
+     class="reftest-wait"
+     onload="setTimeAndSnapshot(1, true)">
+  <title>Test animation of the 'points' attribute on the 'polygon' element</title>
+  <script xlink:href="smil-util.js" type="text/javascript"/>
+  <style type="text/css">
+    polygon { fill: blue; }
+  </style>
+
+
+  <!-- The difference between respective numbers in the effective 'from' and
+       'to' lists below is carefully designed to be a factor of 3. That way
+       our reference file (which checks against a one third complete animation)
+       can contain whole numbers, which is necessary to avoid failure due to
+       hard coded rounded numbers in the reference not matching platform
+       specific rounding behaviour.
+    -->
+
+  <!-- Test 'to' animation. -->
+
+  <polygon points="10,10 70,70 110,10 160,10 210,10">
+    <animate attributeName="points"
+             calcMode="linear"
+             begin="0s" dur="3s"
+             to="10,10 70,10 110,10 160,70 210,10"
+             fill="freeze"/>
+  </polygon>
+
+
+  <!-- Test 'by' animation. -->
+
+  <polygon transform="translate(0, 70)"
+           points="10,10 70,70 110,10 160,10 210,10">
+    <animate attributeName="points"
+             calcMode="linear"
+             begin="0s" dur="3s"
+             by="0,0 0,-60 0,0 0,60 0,0"
+             fill="freeze"/>
+  </polygon>
+
+
+  <!-- Test calcMode="paced". We don't currently support paced animation, so
+       we're just testing that we don't do anything unexpected (that we behave
+       as if calcMode="discrete").
+  -->
+
+  <polygon transform="translate(0, 140)">
+    <animate attributeName="points"
+             calcMode="paced"
+             begin="0s" dur="3s"
+             values="10,10 70,70 110,10 160,10 210,10;
+                     10,10 70,30 110,10 160,50 210,10;
+                     10,10 70,10 110,10 160,70 210,10"
+             fill="freeze"/>
+  </polygon>
+
+
+  <!-- Test calcMode="discrete". -->
+
+  <polygon transform="translate(0, 210)"
+           points="10,10 70,70 110,10 160,10 210,10">
+    <animate attributeName="points"
+             calcMode="discrete"
+             begin="0s" dur="20s"
+             to="10,10 70,10 110,10 160,70 210,10"
+             fill="freeze"/>
+  </polygon>
+
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/smil/anim-polyline-points-01-ref.svg
@@ -0,0 +1,17 @@
+<svg xmlns="http://www.w3.org/2000/svg">
+  <style type="text/css">
+    polyline { fill: none; stroke: blue; stroke-width: 2px; }
+  </style>
+
+  <polyline points="10,10 70,50 110,10 160,30 210,10"/>
+
+  <polyline transform="translate(0, 70)"
+            points="10,10 70,50 110,10 160,30 210,10"/>
+
+  <polyline transform="translate(0, 140)"
+            points="10,10 70,50 110,10 160,30 210,10"/>
+
+  <polyline transform="translate(0, 210)"
+            points="10,10 70,10 110,10 160,70 210,10"/>
+
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/smil/anim-polyline-points-01.svg
@@ -0,0 +1,73 @@
+<!--
+  From https://bugzilla.mozilla.org/show_bug.cgi?id=522308
+-->
+<svg xmlns="http://www.w3.org/2000/svg"
+     xmlns:xlink="http://www.w3.org/1999/xlink"
+     class="reftest-wait"
+     onload="setTimeAndSnapshot(1, true)">
+  <title>Test animation of the 'points' attribute on the 'polyline' element</title>
+  <script xlink:href="smil-util.js" type="text/javascript"/>
+  <style type="text/css">
+    polyline { fill: none; stroke: blue; stroke-width: 2px; }
+  </style>
+
+
+  <!-- The difference between respective numbers in the effective 'from' and
+       'to' lists below is carefully designed to be a factor of 3. That way
+       our reference file (which checks against a one third complete animation)
+       can contain whole numbers, which is necessary to avoid failure due to
+       hard coded rounded numbers in the reference not matching platform
+       specific rounding behaviour.
+    -->
+
+  <!-- Test 'to' animation. -->
+
+  <polyline points="10,10 70,70 110,10 160,10 210,10">
+    <animate attributeName="points"
+             calcMode="linear"
+             begin="0s" dur="3s"
+             to="10,10 70,10 110,10 160,70 210,10"
+             fill="freeze"/>
+  </polyline>
+
+
+  <!-- Test 'by' animation. -->
+
+  <polyline transform="translate(0, 70)"
+            points="10,10 70,70 110,10 160,10 210,10">
+    <animate attributeName="points"
+             calcMode="linear"
+             begin="0s" dur="3s"
+             by="0,0 0,-60 0,0 0,60 0,0"
+             fill="freeze"/>
+  </polyline>
+
+
+  <!-- Test calcMode="paced". We don't currently support paced animation, so
+       we're just testing that we don't do anything unexpected (that we behave
+       as if calcMode="discrete").
+  -->
+
+  <polyline transform="translate(0, 140)">
+    <animate attributeName="points"
+             calcMode="paced"
+             begin="0s" dur="3s"
+             values="10,10 70,70 110,10 160,10 210,10;
+                     10,10 70,30 110,10 160,50 210,10;
+                     10,10 70,10 110,10 160,70 210,10"
+             fill="freeze"/>
+  </polyline>
+
+
+  <!-- Test calcMode="discrete". -->
+
+  <polyline transform="translate(0, 210)"
+            points="10,10 70,70 110,10 160,10 210,10">
+    <animate attributeName="points"
+             calcMode="discrete"
+             begin="0s" dur="20s"
+             to="10,10 70,10 110,10 160,70 210,10"
+             fill="freeze"/>
+  </polyline>
+
+</svg>
--- a/layout/reftests/svg/smil/reftest.list
+++ b/layout/reftests/svg/smil/reftest.list
@@ -96,16 +96,20 @@ fails == anim-fillcolor-1.svg      anim-
 == anim-pathLength-01.svg anim-pathLength-01-ref.svg
 
 # animate some <integer> attributes:
 == anim-feTurbulence-numOctaves-01.svg anim-feTurbulence-numOctaves-01-ref.svg
 
 # animate some <angle> attributes:
 == anim-marker-orient-01.svg lime.svg
 
+#animate points list:
+== anim-polygon-points-01.svg anim-polygon-points-01-ref.svg
+== anim-polyline-points-01.svg anim-polyline-points-01-ref.svg
+
 # animate path data:
 == anim-path-d-01.svg anim-path-d-01-ref.svg
 
 # animate some enumeration attributes:
 == anim-feComposite-operator-01.svg lime.svg
 == anim-filter-filterUnits-01.svg lime.svg
 
 # animate some boolean attributes:
--- a/layout/svg/base/src/nsSVGGlyphFrame.cpp
+++ b/layout/svg/base/src/nsSVGGlyphFrame.cpp
@@ -38,21 +38,20 @@
 
 #include "nsSVGTextFrame.h"
 #include "nsILookAndFeel.h"
 #include "nsTextFragment.h"
 #include "nsSVGUtils.h"
 #include "SVGLengthList.h"
 #include "nsIDOMSVGLength.h"
 #include "nsIDOMSVGRect.h"
-#include "nsIDOMSVGPoint.h"
+#include "DOMSVGPoint.h"
 #include "nsSVGGlyphFrame.h"
 #include "nsSVGTextPathFrame.h"
 #include "nsSVGPathElement.h"
-#include "nsSVGPoint.h"
 #include "nsSVGRect.h"
 #include "nsDOMError.h"
 #include "gfxContext.h"
 #include "gfxMatrix.h"
 #include "gfxPlatform.h"
 #include "gfxTextRunWordCache.h"
 
 using namespace mozilla;
@@ -1094,34 +1093,36 @@ nsSVGGlyphFrame::GetStartPositionOfChar(
                                         nsIDOMSVGPoint **_retval)
 {
   *_retval = nsnull;
 
   CharacterIterator iter(this, PR_FALSE);
   if (!iter.AdvanceToCharacter(charnum))
     return NS_ERROR_DOM_INDEX_SIZE_ERR;
 
-  return NS_NewSVGPoint(_retval, iter.GetPositionData().pos);
+  NS_ADDREF(*_retval = new DOMSVGPoint(iter.GetPositionData().pos));
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSVGGlyphFrame::GetEndPositionOfChar(PRUint32 charnum,
                                       nsIDOMSVGPoint **_retval)
 {
   *_retval = nsnull;
 
   CharacterIterator iter(this, PR_FALSE);
   if (!iter.AdvanceToCharacter(charnum))
     return NS_ERROR_DOM_INDEX_SIZE_ERR;
 
   nsRefPtr<gfxContext> tmpCtx = MakeTmpCtx();
   iter.SetupForMetrics(tmpCtx);
   tmpCtx->MoveTo(gfxPoint(mTextRun->GetAdvanceWidth(charnum, 1, nsnull), 0));
   tmpCtx->IdentityMatrix();
-  return NS_NewSVGPoint(_retval, tmpCtx->CurrentPoint());
+  NS_ADDREF(*_retval = new DOMSVGPoint(tmpCtx->CurrentPoint()));
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSVGGlyphFrame::GetExtentOfChar(PRUint32 charnum, nsIDOMSVGRect **_retval)
 {
   *_retval = nsnull;
 
   CharacterIterator iter(this, PR_FALSE);
--- a/layout/svg/base/src/nsSVGUtils.cpp
+++ b/layout/svg/base/src/nsSVGUtils.cpp
@@ -52,18 +52,16 @@
 #include "nsISVGGlyphFragmentLeaf.h"
 #include "nsNetUtil.h"
 #include "nsFrameList.h"
 #include "nsISVGChildFrame.h"
 #include "nsContentDLF.h"
 #include "nsContentUtils.h"
 #include "nsSVGFilterFrame.h"
 #include "nsINameSpaceManager.h"
-#include "nsIDOMSVGPoint.h"
-#include "nsSVGPoint.h"
 #include "nsDOMError.h"
 #include "nsSVGOuterSVGFrame.h"
 #include "nsSVGInnerSVGFrame.h"
 #include "nsSVGPreserveAspectRatio.h"
 #include "nsSVGMatrix.h"
 #include "nsSVGClipPathFrame.h"
 #include "nsSVGMaskFrame.h"
 #include "nsSVGContainerFrame.h"