Bug 522306. Add support for SMIL animation of the <path> element's 'd' attribute. r=roc, r=longsonr, r=dholbert, a=roc.
authorJonathan Watt <jwatt@jwatt.org>
Mon, 08 Nov 2010 15:07:00 +0000
changeset 57113 7907a5f284900722708efec2245205bdbbb1f3df
parent 57112 07988ddcfe841bed2cf29652bd3e6eaa0cb976e7
child 57114 14e52c423e546b5da12647b2db2f6e7f1f8a060c
push idunknown
push userunknown
push dateunknown
reviewersroc, longsonr, dholbert, roc
bugs522306
milestone2.0b8pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 522306. Add support for SMIL animation of the <path> element's 'd' attribute. r=roc, r=longsonr, r=dholbert, a=roc.
content/smil/test/smilAnimateMotionValueLists.js
content/smil/test/test_smilAnimateMotionInvalidValues.xhtml
content/svg/content/src/DOMSVGPathSeg.cpp
content/svg/content/src/DOMSVGPathSeg.h
content/svg/content/src/DOMSVGPathSegList.cpp
content/svg/content/src/DOMSVGPathSegList.h
content/svg/content/src/Makefile.in
content/svg/content/src/SVGAnimatedPathSegList.cpp
content/svg/content/src/SVGAnimatedPathSegList.h
content/svg/content/src/SVGMotionSMILAnimationFunction.cpp
content/svg/content/src/SVGMotionSMILAnimationFunction.h
content/svg/content/src/SVGMotionSMILType.cpp
content/svg/content/src/SVGPathData.cpp
content/svg/content/src/SVGPathData.h
content/svg/content/src/SVGPathSegListSMILType.cpp
content/svg/content/src/SVGPathSegListSMILType.h
content/svg/content/src/SVGPathSegUtils.cpp
content/svg/content/src/SVGPathSegUtils.h
content/svg/content/src/nsSVGAnimateMotionElement.h
content/svg/content/src/nsSVGElement.cpp
content/svg/content/src/nsSVGElement.h
content/svg/content/src/nsSVGPathDataParser.cpp
content/svg/content/src/nsSVGPathDataParser.h
content/svg/content/src/nsSVGPathElement.cpp
content/svg/content/src/nsSVGPathElement.h
content/svg/content/src/nsSVGPathSeg.cpp
content/svg/content/src/nsSVGPathSeg.h
content/svg/content/src/nsSVGPathSegList.cpp
content/svg/content/src/nsSVGPathSegList.h
content/svg/content/test/test_SVGxxxList.xhtml
layout/reftests/svg/smil/anim-path-d-01-ref.svg
layout/reftests/svg/smil/anim-path-d-01.svg
layout/reftests/svg/smil/reftest.list
--- a/content/smil/test/smilAnimateMotionValueLists.js
+++ b/content/smil/test/smilAnimateMotionValueLists.js
@@ -108,17 +108,23 @@ const gInvalidToBy = [
 const gValidPath = [
  "m0 0     L30 30",
  "M20,20L10    10",
  "M20,20 L30, 30h20",
  "m50 50", "M50 50",
  "m0 0", "M0, 0"
 ];
 
+// paths must start with at least a valid "M" segment to be valid
 const gInvalidPath = [
- "m0 0 L30,,30",
- "M20 20em",
  "M20in 20",
  "h30",
  "L50 50",
  "abc",
+];
+
+// paths that at least start with a valid "M" segment are valid - the spec says
+// to parse everything up to the first invalid token
+const gValidPathWithErrors = [
+ "M20 20em",
+ "m0 0 L30,,30",
  "M10 10 L50 50 abc",
 ];
--- a/content/smil/test/test_smilAnimateMotionInvalidValues.xhtml
+++ b/content/smil/test/test_smilAnimateMotionInvalidValues.xhtml
@@ -152,16 +152,17 @@ function main()
   testAttr("to", gValidToBy, true, false);
   testAttr("to", gInvalidToBy, false, false);
 
   testAttr("by", gValidToBy, true, false);
   testAttr("by", gInvalidToBy, false, false);
 
   testAttr("path", gValidPath, true, false);
   testAttr("path", gInvalidPath, false, false);
+  testAttr("path", gValidPathWithErrors, true, false);
 
   testMpathElem(gValidPath, true, false);
   testMpathElem(gInvalidPath, false, false);
 
   SimpleTest.finish();
 }
 
 window.addEventListener("load", main, false);
new file mode 100644
--- /dev/null
+++ b/content/svg/content/src/DOMSVGPathSeg.cpp
@@ -0,0 +1,1056 @@
+/* -*- 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 "DOMSVGPathSeg.h"
+#include "DOMSVGPathSegList.h"
+#include "SVGPathSegUtils.h"
+#include "SVGAnimatedPathSegList.h"
+#include "nsSVGElement.h"
+#include "nsIDOMSVGPathSeg.h"
+#include "nsDOMError.h"
+
+// See the architecture comment in DOMSVGPathSegList.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(DOMSVGPathSeg)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMSVGPathSeg)
+  // We may not belong to a list, so we must null check tmp->mList.
+  if (tmp->mList) {
+    tmp->mList->ItemAt(tmp->mListIndex) = nsnull;
+  }
+NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mList)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMSVGPathSeg)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mList)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMSVGPathSeg)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMSVGPathSeg)
+
+DOMCI_DATA(SVGPathSeg, DOMSVGPathSeg)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGPathSeg)
+  NS_INTERFACE_MAP_ENTRY(DOMSVGPathSeg) // pseudo-interface
+  NS_INTERFACE_MAP_ENTRY(nsIDOMSVGPathSeg)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+
+DOMSVGPathSeg::DOMSVGPathSeg(DOMSVGPathSegList *aList,
+                             PRUint32 aListIndex,
+                             PRBool aIsAnimValItem)
+  : mList(aList)
+  , mListIndex(aListIndex)
+  , mIsAnimValItem(aIsAnimValItem)
+{
+  // These shifts are in sync with the members in the header.
+  NS_ABORT_IF_FALSE(aList &&
+                    aListIndex < (1U << 31), "bad arg");
+
+  NS_ABORT_IF_FALSE(IndexIsValid(), "Bad index for DOMSVGPathSeg!");
+}
+
+DOMSVGPathSeg::DOMSVGPathSeg()
+  : mList(nsnull)
+  , mListIndex(0)
+  , mIsAnimValItem(PR_FALSE)
+{
+}
+
+NS_IMETHODIMP
+DOMSVGPathSeg::GetPathSegType(PRUint16 *aPathSegType)
+{
+  *aPathSegType = PRUint16(Type());
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DOMSVGPathSeg::GetPathSegTypeAsLetter(nsAString &aPathSegTypeAsLetter)
+{
+  aPathSegTypeAsLetter = SVGPathSegUtils::GetPathSegTypeAsLetter(Type());
+  return NS_OK;
+}
+
+void
+DOMSVGPathSeg::InsertingIntoList(DOMSVGPathSegList *aList,
+                                 PRUint32 aListIndex,
+                                 PRBool aIsAnimValItem)
+{
+  NS_ABORT_IF_FALSE(!HasOwner(), "Inserting item that is already in a list");
+
+  mList = aList;
+  mListIndex = aListIndex;
+  mIsAnimValItem = aIsAnimValItem;
+
+  NS_ABORT_IF_FALSE(IndexIsValid(), "Bad index for DOMSVGPathSeg!");
+}
+
+void
+DOMSVGPathSeg::RemovingFromList()
+{
+  PRUint32 argCount = SVGPathSegUtils::ArgCountForType(Type());
+  // InternalItem() + 1, because the args come after the encoded seg type
+  memcpy(PtrToMemberArgs(), InternalItem() + 1, argCount * sizeof(float));
+  mList = nsnull;
+  mIsAnimValItem = PR_FALSE;
+}
+
+void
+DOMSVGPathSeg::ToSVGPathSegEncodedData(float* aRaw)
+{
+  NS_ABORT_IF_FALSE(aRaw, "null pointer");
+  PRUint32 argCount = SVGPathSegUtils::ArgCountForType(Type());
+  if (IsInList()) {
+    // 1 + argCount, because we're copying the encoded seg type and args
+    memcpy(aRaw, InternalItem(), (1 + argCount) * sizeof(float));
+  } else {
+    aRaw[0] = SVGPathSegUtils::EncodeType(Type());
+    // aRaw + 1, because the args go after the encoded seg type
+    memcpy(aRaw + 1, PtrToMemberArgs(), argCount * sizeof(float));
+  }
+}
+
+float*
+DOMSVGPathSeg::InternalItem()
+{
+  PRUint32 dataIndex = mList->mItems[mListIndex].mInternalDataIndex;
+  return &(mList->InternalList().mData[dataIndex]);
+}
+
+#ifdef DEBUG
+PRBool
+DOMSVGPathSeg::IndexIsValid()
+{
+  SVGAnimatedPathSegList *alist = Element()->GetAnimPathSegList();
+  return (mIsAnimValItem &&
+          mListIndex < alist->GetAnimValue().CountItems()) ||
+         (!mIsAnimValItem &&
+          mListIndex < alist->GetBaseValue().CountItems());
+}
+#endif
+
+
+////////////////////////////////////////////////////////////////////////
+// Implementation of DOMSVGPathSeg sub-classes below this point
+
+#define CHECK_ARG_COUNT_IN_SYNC(segType)                                      \
+          NS_ABORT_IF_FALSE(NS_ARRAY_LENGTH(mArgs) ==                         \
+            SVGPathSegUtils::ArgCountForType(PRUint32(segType)) ||            \
+            PRUint32(segType) == nsIDOMSVGPathSeg::PATHSEG_CLOSEPATH,         \
+            "Arg count/array size out of sync")
+
+#define IMPL_SVGPATHSEG_SUBCLASS_COMMON(segName, segType)                     \
+  DOMSVGPathSeg##segName(const float *aArgs)                                  \
+    : DOMSVGPathSeg()                                                         \
+  {                                                                           \
+    CHECK_ARG_COUNT_IN_SYNC(segType);                                         \
+    memcpy(mArgs, aArgs,                                                      \
+        SVGPathSegUtils::ArgCountForType(PRUint32(segType)) * sizeof(float)); \
+  }                                                                           \
+  DOMSVGPathSeg##segName(DOMSVGPathSegList *aList,                            \
+                         PRUint32 aListIndex,                                 \
+                         PRBool aIsAnimValItem)                               \
+    : DOMSVGPathSeg(aList, aListIndex, aIsAnimValItem)                        \
+  {                                                                           \
+    CHECK_ARG_COUNT_IN_SYNC(segType);                                         \
+  }                                                                           \
+  /* From DOMSVGPathSeg: */                                                   \
+  virtual PRUint32                                                            \
+  Type() const                                                                \
+  {                                                                           \
+    return segType;                                                           \
+  }                                                                           \
+  virtual DOMSVGPathSeg*                                                      \
+  Clone()                                                                     \
+  {                                                                           \
+    /* InternalItem() + 1, because we're skipping the encoded seg type */     \
+    float *args = IsInList() ? InternalItem() + 1 : mArgs;                    \
+    return new DOMSVGPathSeg##segName(args);                                  \
+  }                                                                           \
+  virtual float*                                                              \
+  PtrToMemberArgs()                                                           \
+  {                                                                           \
+    return mArgs;                                                             \
+  }
+
+#define IMPL_NSISUPPORTS_SVGPATHSEG_SUBCLASS(segName)                         \
+  /* Forward to the CYCLE_COLLECTING_ADDREF on our base class */              \
+  NS_IMPL_ADDREF_INHERITED(DOMSVGPathSeg##segName, DOMSVGPathSeg)             \
+  NS_IMPL_RELEASE_INHERITED(DOMSVGPathSeg##segName, DOMSVGPathSeg)            \
+                                                                              \
+  DOMCI_DATA(SVGPathSeg##segName, DOMSVGPathSeg##segName)                     \
+                                                                              \
+  NS_INTERFACE_MAP_BEGIN(DOMSVGPathSeg##segName)                              \
+    NS_INTERFACE_MAP_ENTRY(nsIDOMSVGPathSeg##segName)                         \
+    NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGPathSeg##segName)                 \
+  NS_INTERFACE_MAP_END_INHERITING(DOMSVGPathSeg)
+
+#define IMPL_PROP_WITH_TYPE(segName, propName, index, type)                   \
+  /* attribute type propName; */                                              \
+  NS_IMETHODIMP                                                               \
+  DOMSVGPathSeg##segName::Get##propName(type *a##propName)                    \
+  {                                                                           \
+    if (mIsAnimValItem && HasOwner()) {                                       \
+      Element()->FlushAnimations(); /* May make HasOwner() == PR_FALSE */     \
+    }                                                                         \
+    *a##propName = type(HasOwner() ? InternalItem()[1+index] : mArgs[index]); \
+    return NS_OK;                                                             \
+  }                                                                           \
+  NS_IMETHODIMP                                                               \
+  DOMSVGPathSeg##segName::Set##propName(type a##propName)                     \
+  {                                                                           \
+    if (mIsAnimValItem) {                                                     \
+      return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;                        \
+    }                                                                         \
+    NS_ENSURE_FINITE(float(a##propName), NS_ERROR_ILLEGAL_VALUE);             \
+    if (HasOwner()) {                                                         \
+      InternalItem()[1+index] = float(a##propName);                           \
+      NS_ABORT_IF_FALSE(IsInList(), "DidChangePathSegList() is wrong");       \
+      Element()->DidChangePathSegList(PR_TRUE);                               \
+      if (mList->AttrIsAnimating()) {                                         \
+        Element()->AnimationNeedsResample();                                  \
+      }                                                                       \
+    } else {                                                                  \
+      mArgs[index] = float(a##propName);                                      \
+    }                                                                         \
+    return NS_OK;                                                             \
+  }
+
+// For float, the normal type of arguments
+#define IMPL_FLOAT_PROP(segName, propName, index) \
+  IMPL_PROP_WITH_TYPE(segName, propName, index, float)
+
+// For the boolean flags in arc commands
+#define IMPL_BOOL_PROP(segName, propName, index) \
+  IMPL_PROP_WITH_TYPE(segName, propName, index, PRBool)
+
+
+////////////////////////////////////////////////////////////////////////
+
+class DOMSVGPathSegClosePath
+  : public DOMSVGPathSeg
+  , public nsIDOMSVGPathSegClosePath
+{
+public:
+  DOMSVGPathSegClosePath()
+    : DOMSVGPathSeg()
+  {
+  }
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIDOMSVGPATHSEGCLOSEPATH
+  IMPL_SVGPATHSEG_SUBCLASS_COMMON(ClosePath, PATHSEG_CLOSEPATH)
+
+protected:
+  // To allow IMPL_SVGPATHSEG_SUBCLASS_COMMON above to compile we need an
+  // mArgs, but since C++ doesn't allow zero-sized arrays we need to give it
+  // one (unused) element.
+  float mArgs[1];
+};
+
+IMPL_NSISUPPORTS_SVGPATHSEG_SUBCLASS(ClosePath)
+
+
+////////////////////////////////////////////////////////////////////////
+
+class DOMSVGPathSegMovetoAbs
+  : public DOMSVGPathSeg
+  , public nsIDOMSVGPathSegMovetoAbs
+{
+public:
+  DOMSVGPathSegMovetoAbs(float x, float y)
+    : DOMSVGPathSeg()
+  {
+    mArgs[0] = x;
+    mArgs[1] = y;
+  }
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIDOMSVGPATHSEGMOVETOABS
+  IMPL_SVGPATHSEG_SUBCLASS_COMMON(MovetoAbs, PATHSEG_MOVETO_ABS)
+
+protected:
+  float mArgs[2];
+};
+
+IMPL_NSISUPPORTS_SVGPATHSEG_SUBCLASS(MovetoAbs)
+
+IMPL_FLOAT_PROP(MovetoAbs, X, 0)
+IMPL_FLOAT_PROP(MovetoAbs, Y, 1)
+
+
+////////////////////////////////////////////////////////////////////////
+
+class DOMSVGPathSegMovetoRel
+  : public DOMSVGPathSeg
+  , public nsIDOMSVGPathSegMovetoRel
+{
+public:
+  DOMSVGPathSegMovetoRel(float x, float y)
+    : DOMSVGPathSeg()
+  {
+    mArgs[0] = x;
+    mArgs[1] = y;
+  }
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIDOMSVGPATHSEGMOVETOREL
+  IMPL_SVGPATHSEG_SUBCLASS_COMMON(MovetoRel, PATHSEG_MOVETO_REL)
+
+protected:
+  float mArgs[2];
+};
+
+IMPL_NSISUPPORTS_SVGPATHSEG_SUBCLASS(MovetoRel)
+
+IMPL_FLOAT_PROP(MovetoRel, X, 0)
+IMPL_FLOAT_PROP(MovetoRel, Y, 1)
+
+
+
+////////////////////////////////////////////////////////////////////////
+
+class DOMSVGPathSegLinetoAbs
+  : public DOMSVGPathSeg
+  , public nsIDOMSVGPathSegLinetoAbs
+{
+public:
+  DOMSVGPathSegLinetoAbs(float x, float y)
+    : DOMSVGPathSeg()
+  {
+    mArgs[0] = x;
+    mArgs[1] = y;
+  }
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIDOMSVGPATHSEGLINETOABS
+  IMPL_SVGPATHSEG_SUBCLASS_COMMON(LinetoAbs, PATHSEG_LINETO_ABS)
+
+protected:
+  float mArgs[2];
+};
+
+IMPL_NSISUPPORTS_SVGPATHSEG_SUBCLASS(LinetoAbs)
+
+IMPL_FLOAT_PROP(LinetoAbs, X, 0)
+IMPL_FLOAT_PROP(LinetoAbs, Y, 1)
+
+
+////////////////////////////////////////////////////////////////////////
+
+class DOMSVGPathSegLinetoRel
+  : public DOMSVGPathSeg
+  , public nsIDOMSVGPathSegLinetoRel
+{
+public:
+  DOMSVGPathSegLinetoRel(float x, float y)
+    : DOMSVGPathSeg()
+  {
+    mArgs[0] = x;
+    mArgs[1] = y;
+  }
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIDOMSVGPATHSEGLINETOREL
+  IMPL_SVGPATHSEG_SUBCLASS_COMMON(LinetoRel, PATHSEG_LINETO_REL)
+
+protected:
+  float mArgs[2];
+};
+
+IMPL_NSISUPPORTS_SVGPATHSEG_SUBCLASS(LinetoRel)
+
+IMPL_FLOAT_PROP(LinetoRel, X, 0)
+IMPL_FLOAT_PROP(LinetoRel, Y, 1)
+
+
+////////////////////////////////////////////////////////////////////////
+
+class DOMSVGPathSegCurvetoCubicAbs
+  : public DOMSVGPathSeg
+  , public nsIDOMSVGPathSegCurvetoCubicAbs
+{
+public:
+  DOMSVGPathSegCurvetoCubicAbs(float x1, float y1,
+                               float x2, float y2,
+                               float x, float y)
+    : DOMSVGPathSeg()
+  {
+    mArgs[0] = x1;
+    mArgs[1] = y1;
+    mArgs[2] = x2;
+    mArgs[3] = y2;
+    mArgs[4] = x;
+    mArgs[5] = y;
+  }
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIDOMSVGPATHSEGCURVETOCUBICABS
+  IMPL_SVGPATHSEG_SUBCLASS_COMMON(CurvetoCubicAbs, PATHSEG_CURVETO_CUBIC_ABS)
+
+protected:
+  float mArgs[6];
+};
+
+IMPL_NSISUPPORTS_SVGPATHSEG_SUBCLASS(CurvetoCubicAbs)
+
+IMPL_FLOAT_PROP(CurvetoCubicAbs, X1, 0)
+IMPL_FLOAT_PROP(CurvetoCubicAbs, Y1, 1)
+IMPL_FLOAT_PROP(CurvetoCubicAbs, X2, 2)
+IMPL_FLOAT_PROP(CurvetoCubicAbs, Y2, 3)
+IMPL_FLOAT_PROP(CurvetoCubicAbs, X, 4)
+IMPL_FLOAT_PROP(CurvetoCubicAbs, Y, 5)
+
+
+////////////////////////////////////////////////////////////////////////
+
+class DOMSVGPathSegCurvetoCubicRel
+  : public DOMSVGPathSeg
+  , public nsIDOMSVGPathSegCurvetoCubicRel
+{
+public:
+  DOMSVGPathSegCurvetoCubicRel(float x1, float y1,
+                               float x2, float y2,
+                               float x, float y)
+    : DOMSVGPathSeg()
+  {
+    mArgs[0] = x1;
+    mArgs[1] = y1;
+    mArgs[2] = x2;
+    mArgs[3] = y2;
+    mArgs[4] = x;
+    mArgs[5] = y;
+  }
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIDOMSVGPATHSEGCURVETOCUBICREL
+  IMPL_SVGPATHSEG_SUBCLASS_COMMON(CurvetoCubicRel, PATHSEG_CURVETO_CUBIC_REL)
+
+protected:
+  float mArgs[6];
+};
+
+IMPL_NSISUPPORTS_SVGPATHSEG_SUBCLASS(CurvetoCubicRel)
+
+IMPL_FLOAT_PROP(CurvetoCubicRel, X1, 0)
+IMPL_FLOAT_PROP(CurvetoCubicRel, Y1, 1)
+IMPL_FLOAT_PROP(CurvetoCubicRel, X2, 2)
+IMPL_FLOAT_PROP(CurvetoCubicRel, Y2, 3)
+IMPL_FLOAT_PROP(CurvetoCubicRel, X, 4)
+IMPL_FLOAT_PROP(CurvetoCubicRel, Y, 5)
+
+
+////////////////////////////////////////////////////////////////////////
+
+class DOMSVGPathSegCurvetoQuadraticAbs
+  : public DOMSVGPathSeg
+  , public nsIDOMSVGPathSegCurvetoQuadraticAbs
+{
+public:
+  DOMSVGPathSegCurvetoQuadraticAbs(float x1, float y1,
+                                   float x, float y)
+    : DOMSVGPathSeg()
+  {
+    mArgs[0] = x1;
+    mArgs[1] = y1;
+    mArgs[2] = x;
+    mArgs[3] = y;
+  }
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIDOMSVGPATHSEGCURVETOQUADRATICABS
+  IMPL_SVGPATHSEG_SUBCLASS_COMMON(CurvetoQuadraticAbs, PATHSEG_CURVETO_QUADRATIC_ABS)
+
+protected:
+  float mArgs[4];
+};
+
+IMPL_NSISUPPORTS_SVGPATHSEG_SUBCLASS(CurvetoQuadraticAbs)
+
+IMPL_FLOAT_PROP(CurvetoQuadraticAbs, X1, 0)
+IMPL_FLOAT_PROP(CurvetoQuadraticAbs, Y1, 1)
+IMPL_FLOAT_PROP(CurvetoQuadraticAbs, X, 2)
+IMPL_FLOAT_PROP(CurvetoQuadraticAbs, Y, 3)
+
+
+////////////////////////////////////////////////////////////////////////
+
+class DOMSVGPathSegCurvetoQuadraticRel
+  : public DOMSVGPathSeg
+  , public nsIDOMSVGPathSegCurvetoQuadraticRel
+{
+public:
+  DOMSVGPathSegCurvetoQuadraticRel(float x1, float y1,
+                                   float x, float y)
+    : DOMSVGPathSeg()
+  {
+    mArgs[0] = x1;
+    mArgs[1] = y1;
+    mArgs[2] = x;
+    mArgs[3] = y;
+  }
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIDOMSVGPATHSEGCURVETOQUADRATICREL
+  IMPL_SVGPATHSEG_SUBCLASS_COMMON(CurvetoQuadraticRel, PATHSEG_CURVETO_QUADRATIC_REL)
+
+protected:
+  float mArgs[4];
+};
+
+IMPL_NSISUPPORTS_SVGPATHSEG_SUBCLASS(CurvetoQuadraticRel)
+
+IMPL_FLOAT_PROP(CurvetoQuadraticRel, X1, 0)
+IMPL_FLOAT_PROP(CurvetoQuadraticRel, Y1, 1)
+IMPL_FLOAT_PROP(CurvetoQuadraticRel, X, 2)
+IMPL_FLOAT_PROP(CurvetoQuadraticRel, Y, 3)
+
+
+////////////////////////////////////////////////////////////////////////
+
+class DOMSVGPathSegArcAbs
+  : public DOMSVGPathSeg
+  , public nsIDOMSVGPathSegArcAbs
+{
+public:
+  DOMSVGPathSegArcAbs(float r1, float r2, float angle,
+                      PRBool largeArcFlag, PRBool sweepFlag,
+                      float x, float y)
+    : DOMSVGPathSeg()
+  {
+    mArgs[0] = r1;
+    mArgs[1] = r2;
+    mArgs[2] = angle;
+    mArgs[3] = largeArcFlag;
+    mArgs[4] = sweepFlag;
+    mArgs[5] = x;
+    mArgs[6] = y;
+  }
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIDOMSVGPATHSEGARCABS
+  IMPL_SVGPATHSEG_SUBCLASS_COMMON(ArcAbs, PATHSEG_ARC_ABS)
+
+protected:
+  float mArgs[7];
+};
+
+IMPL_NSISUPPORTS_SVGPATHSEG_SUBCLASS(ArcAbs)
+
+IMPL_FLOAT_PROP(ArcAbs, R1, 0)
+IMPL_FLOAT_PROP(ArcAbs, R2, 1)
+IMPL_FLOAT_PROP(ArcAbs, Angle, 2)
+IMPL_BOOL_PROP(ArcAbs, LargeArcFlag, 3)
+IMPL_BOOL_PROP(ArcAbs, SweepFlag, 4)
+IMPL_FLOAT_PROP(ArcAbs, X, 5)
+IMPL_FLOAT_PROP(ArcAbs, Y, 6)
+
+
+////////////////////////////////////////////////////////////////////////
+
+class DOMSVGPathSegArcRel
+  : public DOMSVGPathSeg
+  , public nsIDOMSVGPathSegArcRel
+{
+public:
+  DOMSVGPathSegArcRel(float r1, float r2, float angle,
+                      PRBool largeArcFlag, PRBool sweepFlag,
+                      float x, float y)
+    : DOMSVGPathSeg()
+  {
+    mArgs[0] = r1;
+    mArgs[1] = r2;
+    mArgs[2] = angle;
+    mArgs[3] = largeArcFlag;
+    mArgs[4] = sweepFlag;
+    mArgs[5] = x;
+    mArgs[6] = y;
+  }
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIDOMSVGPATHSEGARCREL
+  IMPL_SVGPATHSEG_SUBCLASS_COMMON(ArcRel, PATHSEG_ARC_REL)
+
+protected:
+  float mArgs[7];
+};
+
+IMPL_NSISUPPORTS_SVGPATHSEG_SUBCLASS(ArcRel)
+
+IMPL_FLOAT_PROP(ArcRel, R1, 0)
+IMPL_FLOAT_PROP(ArcRel, R2, 1)
+IMPL_FLOAT_PROP(ArcRel, Angle, 2)
+IMPL_BOOL_PROP(ArcRel, LargeArcFlag, 3)
+IMPL_BOOL_PROP(ArcRel, SweepFlag, 4)
+IMPL_FLOAT_PROP(ArcRel, X, 5)
+IMPL_FLOAT_PROP(ArcRel, Y, 6)
+
+
+////////////////////////////////////////////////////////////////////////
+
+class DOMSVGPathSegLinetoHorizontalAbs
+  : public DOMSVGPathSeg
+  , public nsIDOMSVGPathSegLinetoHorizontalAbs
+{
+public:
+  DOMSVGPathSegLinetoHorizontalAbs(float x)
+    : DOMSVGPathSeg()
+  {
+    mArgs[0] = x;
+  }
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIDOMSVGPATHSEGLINETOHORIZONTALABS
+  IMPL_SVGPATHSEG_SUBCLASS_COMMON(LinetoHorizontalAbs, PATHSEG_LINETO_HORIZONTAL_ABS)
+
+protected:
+  float mArgs[1];
+};
+
+IMPL_NSISUPPORTS_SVGPATHSEG_SUBCLASS(LinetoHorizontalAbs)
+
+IMPL_FLOAT_PROP(LinetoHorizontalAbs, X, 0)
+
+
+////////////////////////////////////////////////////////////////////////
+
+class DOMSVGPathSegLinetoHorizontalRel
+  : public DOMSVGPathSeg
+  , public nsIDOMSVGPathSegLinetoHorizontalRel
+{
+public:
+  DOMSVGPathSegLinetoHorizontalRel(float x)
+    : DOMSVGPathSeg()
+  {
+    mArgs[0] = x;
+  }
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIDOMSVGPATHSEGLINETOHORIZONTALREL
+  IMPL_SVGPATHSEG_SUBCLASS_COMMON(LinetoHorizontalRel, PATHSEG_LINETO_HORIZONTAL_REL)
+
+protected:
+  float mArgs[1];
+};
+
+IMPL_NSISUPPORTS_SVGPATHSEG_SUBCLASS(LinetoHorizontalRel)
+
+IMPL_FLOAT_PROP(LinetoHorizontalRel, X, 0)
+
+
+////////////////////////////////////////////////////////////////////////
+
+class DOMSVGPathSegLinetoVerticalAbs
+  : public DOMSVGPathSeg
+  , public nsIDOMSVGPathSegLinetoVerticalAbs
+{
+public:
+  DOMSVGPathSegLinetoVerticalAbs(float y)
+    : DOMSVGPathSeg()
+  {
+    mArgs[0] = y;
+  }
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIDOMSVGPATHSEGLINETOVERTICALABS
+  IMPL_SVGPATHSEG_SUBCLASS_COMMON(LinetoVerticalAbs, PATHSEG_LINETO_VERTICAL_ABS)
+
+protected:
+  float mArgs[1];
+};
+
+IMPL_NSISUPPORTS_SVGPATHSEG_SUBCLASS(LinetoVerticalAbs)
+
+IMPL_FLOAT_PROP(LinetoVerticalAbs, Y, 0)
+
+
+////////////////////////////////////////////////////////////////////////
+
+class DOMSVGPathSegLinetoVerticalRel
+  : public DOMSVGPathSeg
+  , public nsIDOMSVGPathSegLinetoVerticalRel
+{
+public:
+  DOMSVGPathSegLinetoVerticalRel(float y)
+    : DOMSVGPathSeg()
+  {
+    mArgs[0] = y;
+  }
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIDOMSVGPATHSEGLINETOVERTICALREL
+  IMPL_SVGPATHSEG_SUBCLASS_COMMON(LinetoVerticalRel, PATHSEG_LINETO_VERTICAL_REL)
+
+protected:
+  float mArgs[1];
+};
+
+IMPL_NSISUPPORTS_SVGPATHSEG_SUBCLASS(LinetoVerticalRel)
+
+IMPL_FLOAT_PROP(LinetoVerticalRel, Y, 0)
+
+
+////////////////////////////////////////////////////////////////////////
+
+class DOMSVGPathSegCurvetoCubicSmoothAbs
+  : public DOMSVGPathSeg
+  , public nsIDOMSVGPathSegCurvetoCubicSmoothAbs
+{
+public:
+  DOMSVGPathSegCurvetoCubicSmoothAbs(float x2, float y2,
+                                     float x, float y)
+    : DOMSVGPathSeg()
+  {
+    mArgs[0] = x2;
+    mArgs[1] = y2;
+    mArgs[2] = x;
+    mArgs[3] = y;
+  }
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIDOMSVGPATHSEGCURVETOCUBICSMOOTHABS
+  IMPL_SVGPATHSEG_SUBCLASS_COMMON(CurvetoCubicSmoothAbs, PATHSEG_CURVETO_CUBIC_SMOOTH_ABS)
+
+protected:
+  float mArgs[4];
+};
+
+IMPL_NSISUPPORTS_SVGPATHSEG_SUBCLASS(CurvetoCubicSmoothAbs)
+
+IMPL_FLOAT_PROP(CurvetoCubicSmoothAbs, X2, 0)
+IMPL_FLOAT_PROP(CurvetoCubicSmoothAbs, Y2, 1)
+IMPL_FLOAT_PROP(CurvetoCubicSmoothAbs, X, 2)
+IMPL_FLOAT_PROP(CurvetoCubicSmoothAbs, Y, 3)
+
+
+////////////////////////////////////////////////////////////////////////
+
+class DOMSVGPathSegCurvetoCubicSmoothRel
+  : public DOMSVGPathSeg
+  , public nsIDOMSVGPathSegCurvetoCubicSmoothRel
+{
+public:
+  DOMSVGPathSegCurvetoCubicSmoothRel(float x2, float y2,
+                                     float x, float y)
+    : DOMSVGPathSeg()
+  {
+    mArgs[0] = x2;
+    mArgs[1] = y2;
+    mArgs[2] = x;
+    mArgs[3] = y;
+  }
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIDOMSVGPATHSEGCURVETOCUBICSMOOTHREL
+  IMPL_SVGPATHSEG_SUBCLASS_COMMON(CurvetoCubicSmoothRel, PATHSEG_CURVETO_CUBIC_SMOOTH_REL)
+
+protected:
+  float mArgs[4];
+};
+
+IMPL_NSISUPPORTS_SVGPATHSEG_SUBCLASS(CurvetoCubicSmoothRel)
+
+IMPL_FLOAT_PROP(CurvetoCubicSmoothRel, X2, 0)
+IMPL_FLOAT_PROP(CurvetoCubicSmoothRel, Y2, 1)
+IMPL_FLOAT_PROP(CurvetoCubicSmoothRel, X, 2)
+IMPL_FLOAT_PROP(CurvetoCubicSmoothRel, Y, 3)
+
+
+////////////////////////////////////////////////////////////////////////
+
+class DOMSVGPathSegCurvetoQuadraticSmoothAbs
+  : public DOMSVGPathSeg
+  , public nsIDOMSVGPathSegCurvetoQuadraticSmoothAbs
+{
+public:
+  DOMSVGPathSegCurvetoQuadraticSmoothAbs(float x, float y)
+    : DOMSVGPathSeg()
+  {
+    mArgs[0] = x;
+    mArgs[1] = y;
+  }
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIDOMSVGPATHSEGCURVETOQUADRATICSMOOTHABS
+  IMPL_SVGPATHSEG_SUBCLASS_COMMON(CurvetoQuadraticSmoothAbs, PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS)
+
+protected:
+  float mArgs[2];
+};
+
+IMPL_NSISUPPORTS_SVGPATHSEG_SUBCLASS(CurvetoQuadraticSmoothAbs)
+
+IMPL_FLOAT_PROP(CurvetoQuadraticSmoothAbs, X, 0)
+IMPL_FLOAT_PROP(CurvetoQuadraticSmoothAbs, Y, 1)
+
+
+////////////////////////////////////////////////////////////////////////
+
+class DOMSVGPathSegCurvetoQuadraticSmoothRel
+  : public DOMSVGPathSeg
+  , public nsIDOMSVGPathSegCurvetoQuadraticSmoothRel
+{
+public:
+  DOMSVGPathSegCurvetoQuadraticSmoothRel(float x, float y)
+    : DOMSVGPathSeg()
+  {
+    mArgs[0] = x;
+    mArgs[1] = y;
+  }
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIDOMSVGPATHSEGCURVETOQUADRATICSMOOTHREL
+  IMPL_SVGPATHSEG_SUBCLASS_COMMON(CurvetoQuadraticSmoothRel, PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL)
+
+protected:
+  float mArgs[2];
+};
+
+IMPL_NSISUPPORTS_SVGPATHSEG_SUBCLASS(CurvetoQuadraticSmoothRel)
+
+IMPL_FLOAT_PROP(CurvetoQuadraticSmoothRel, X, 0)
+IMPL_FLOAT_PROP(CurvetoQuadraticSmoothRel, Y, 1)
+
+
+
+// This must come after DOMSVGPathSegClosePath et. al. have been declared.
+/* static */ DOMSVGPathSeg*
+DOMSVGPathSeg::CreateFor(DOMSVGPathSegList *aList,
+                         PRUint32 aListIndex,
+                         PRBool aIsAnimValItem)
+{
+  PRUint32 dataIndex = aList->mItems[aListIndex].mInternalDataIndex;
+  float *data = &aList->InternalList().mData[dataIndex];
+  PRUint32 type = SVGPathSegUtils::DecodeType(data[0]);
+
+  switch (type)
+  {
+  case nsIDOMSVGPathSeg::PATHSEG_CLOSEPATH:
+    return new DOMSVGPathSegClosePath(aList, aListIndex, aIsAnimValItem);
+  case nsIDOMSVGPathSeg::PATHSEG_MOVETO_ABS:
+    return new DOMSVGPathSegMovetoAbs(aList, aListIndex, aIsAnimValItem);
+  case nsIDOMSVGPathSeg::PATHSEG_MOVETO_REL:
+    return new DOMSVGPathSegMovetoRel(aList, aListIndex, aIsAnimValItem);
+  case nsIDOMSVGPathSeg::PATHSEG_LINETO_ABS:
+    return new DOMSVGPathSegLinetoAbs(aList, aListIndex, aIsAnimValItem);
+  case nsIDOMSVGPathSeg::PATHSEG_LINETO_REL:
+    return new DOMSVGPathSegLinetoRel(aList, aListIndex, aIsAnimValItem);
+  case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS:
+    return new DOMSVGPathSegCurvetoCubicAbs(aList, aListIndex, aIsAnimValItem);
+  case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_REL:
+    return new DOMSVGPathSegCurvetoCubicRel(aList, aListIndex, aIsAnimValItem);
+  case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_ABS:
+    return new DOMSVGPathSegCurvetoQuadraticAbs(aList, aListIndex, aIsAnimValItem);
+  case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_REL:
+    return new DOMSVGPathSegCurvetoQuadraticRel(aList, aListIndex, aIsAnimValItem);
+  case nsIDOMSVGPathSeg::PATHSEG_ARC_ABS:
+    return new DOMSVGPathSegArcAbs(aList, aListIndex, aIsAnimValItem);
+  case nsIDOMSVGPathSeg::PATHSEG_ARC_REL:
+    return new DOMSVGPathSegArcRel(aList, aListIndex, aIsAnimValItem);
+  case nsIDOMSVGPathSeg::PATHSEG_LINETO_HORIZONTAL_ABS:
+    return new DOMSVGPathSegLinetoHorizontalAbs(aList, aListIndex, aIsAnimValItem);
+  case nsIDOMSVGPathSeg::PATHSEG_LINETO_HORIZONTAL_REL:
+    return new DOMSVGPathSegLinetoHorizontalRel(aList, aListIndex, aIsAnimValItem);
+  case nsIDOMSVGPathSeg::PATHSEG_LINETO_VERTICAL_ABS:
+    return new DOMSVGPathSegLinetoVerticalAbs(aList, aListIndex, aIsAnimValItem);
+  case nsIDOMSVGPathSeg::PATHSEG_LINETO_VERTICAL_REL:
+    return new DOMSVGPathSegLinetoVerticalRel(aList, aListIndex, aIsAnimValItem);
+  case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS:
+    return new DOMSVGPathSegCurvetoCubicSmoothAbs(aList, aListIndex, aIsAnimValItem);
+  case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_REL:
+    return new DOMSVGPathSegCurvetoCubicSmoothRel(aList, aListIndex, aIsAnimValItem);
+  case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS:
+    return new DOMSVGPathSegCurvetoQuadraticSmoothAbs(aList, aListIndex, aIsAnimValItem);
+  case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL:
+    return new DOMSVGPathSegCurvetoQuadraticSmoothRel(aList, aListIndex, aIsAnimValItem);
+  default:
+    NS_NOTREACHED("Invalid path segment type");
+    return nsnull;
+  }
+}
+
+
+
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegClosePath()
+{
+  return new DOMSVGPathSegClosePath();
+}
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegMovetoAbs(float x, float y)
+{
+  return new DOMSVGPathSegMovetoAbs(x, y);
+}
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegMovetoRel(float x, float y)
+{
+  return new DOMSVGPathSegMovetoRel(x, y);
+}
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegLinetoAbs(float x, float y)
+{
+  return new DOMSVGPathSegLinetoAbs(x, y);
+}
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegLinetoRel(float x, float y)
+{
+  return new DOMSVGPathSegLinetoRel(x, y);
+}
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegCurvetoCubicAbs(float x, float y,
+                                float x1, float y1,
+                                float x2, float y2)
+{
+  // Note that we swap from DOM API argument order to the argument order used
+  // in the <path> element's 'd' attribute (i.e. we put the arguments for the
+  // end point of the segment last instead of first).
+
+  return new DOMSVGPathSegCurvetoCubicAbs(x1, y1, x2, y2, x, y);
+}
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegCurvetoCubicRel(float x, float y,
+                                float x1, float y1,
+                                float x2, float y2)
+{
+  // See comment in NS_NewSVGPathSegCurvetoCubicAbs!
+
+  return new DOMSVGPathSegCurvetoCubicRel(x1, y1, x2, y2, x, y);
+}
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegCurvetoQuadraticAbs(float x, float y,
+                                    float x1, float y1)
+{
+  // See comment in NS_NewSVGPathSegCurvetoCubicAbs!
+
+  return new DOMSVGPathSegCurvetoQuadraticAbs(x1, y1, x, y);
+}
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegCurvetoQuadraticRel(float x, float y,
+                                    float x1, float y1)
+{
+  // See comment in NS_NewSVGPathSegCurvetoCubicAbs!
+
+  return new DOMSVGPathSegCurvetoQuadraticRel(x1, y1, x, y);
+}
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegArcAbs(float x, float y,
+                       float r1, float r2, float angle,
+                       PRBool largeArcFlag, PRBool sweepFlag)
+{
+  // See comment in NS_NewSVGPathSegCurvetoCubicAbs!
+
+  return new DOMSVGPathSegArcAbs(r1, r2, angle, largeArcFlag, sweepFlag, x, y);
+}
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegArcRel(float x, float y,
+                       float r1, float r2, float angle,
+                       PRBool largeArcFlag, PRBool sweepFlag)
+{
+  // See comment in NS_NewSVGPathSegCurvetoCubicAbs!
+
+  return new DOMSVGPathSegArcRel(r1, r2, angle, largeArcFlag, sweepFlag, x, y);
+}
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegLinetoHorizontalAbs(float x)
+{
+  return new DOMSVGPathSegLinetoHorizontalAbs(x);
+}
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegLinetoHorizontalRel(float x)
+{
+  return new DOMSVGPathSegLinetoHorizontalRel(x);
+}
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegLinetoVerticalAbs(float y)
+{
+  return new DOMSVGPathSegLinetoVerticalAbs(y);
+}
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegLinetoVerticalRel(float y)
+{
+  return new DOMSVGPathSegLinetoVerticalRel(y);
+}
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegCurvetoCubicSmoothAbs(float x, float y,
+                                      float x2, float y2)
+{
+  // See comment in NS_NewSVGPathSegCurvetoCubicAbs!
+
+  return new DOMSVGPathSegCurvetoCubicSmoothAbs(x2, y2, x, y);
+}
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegCurvetoCubicSmoothRel(float x, float y,
+                                      float x2, float y2)
+{
+  // See comment in NS_NewSVGPathSegCurvetoCubicAbs!
+
+  return new DOMSVGPathSegCurvetoCubicSmoothRel(x2, y2, x, y);
+}
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegCurvetoQuadraticSmoothAbs(float x, float y)
+{
+  return new DOMSVGPathSegCurvetoQuadraticSmoothAbs(x, y);
+}
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegCurvetoQuadraticSmoothRel(float x, float y)
+{
+  return new DOMSVGPathSegCurvetoQuadraticSmoothRel(x, y);
+}
+
new file mode 100644
--- /dev/null
+++ b/content/svg/content/src/DOMSVGPathSeg.h
@@ -0,0 +1,276 @@
+/* -*- 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_DOMSVGPATHSEG_H__
+#define MOZILLA_DOMSVGPATHSEG_H__
+
+#include "nsIDOMSVGPathSeg.h"
+#include "DOMSVGPathSegList.h"
+#include "SVGPathSegUtils.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsAutoPtr.h"
+
+class nsSVGElement;
+
+// We make DOMSVGPathSeg a pseudo-interface to allow us to QI to it in order to
+// check that the objects that scripts pass to DOMSVGPathSegList methods are
+// our *native* path seg objects.
+//
+// {494A7566-DC26-40C8-9122-52ABD76870C4}
+#define MOZILLA_DOMSVGPATHSEG_IID \
+  { 0x494A7566, 0xDC26, 0x40C8, { 0x91, 0x22, 0x52, 0xAB, 0xD7, 0x68, 0x70, 0xC4 } }
+
+namespace mozilla {
+
+/**
+ * Class DOMSVGPathSeg
+ *
+ * This class is the base class of the classes that create the DOM objects that
+ * wrap the internal path segments that are encoded in an SVGPathData. Its
+ * sub-classes are also used to create the objects returned by
+ * SVGPathElement.createSVGPathSegXxx().
+ *
+ * See the architecture comment in DOMSVGPathSegList.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.
+ *
+ * The main differences between this class and DOMSVGLength is that we have
+ * sub-classes (it does not), and the "internal counterpart" that we provide a
+ * DOM wrapper for is a list of floats, not an instance of an internal class.
+ */
+class DOMSVGPathSeg : public nsIDOMSVGPathSeg
+{
+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.
+   */
+  static DOMSVGPathSeg *CreateFor(DOMSVGPathSegList *aList,
+                                  PRUint32 aListIndex,
+                                  PRBool aIsAnimValItem);
+
+  /**
+   * Create an unowned copy of this object. The caller is responsible for the
+   * first AddRef()!
+   */
+  virtual DOMSVGPathSeg* Clone() = 0;
+
+  PRBool IsInList() const {
+    return !!mList;
+  }
+
+  /**
+   * In future, if this class is used for non-list segments, this will be
+   * different to IsInList().
+   */
+  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 DOMSVGPathSegList).)
+   */
+  void InsertingIntoList(DOMSVGPathSegList *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();
+
+  /**
+   * This method converts the segment to a string of floats as found in
+   * SVGPathData (i.e. the first float contains the type of the segment,
+   * encoded into a float, followed by its arguments in the same order as they
+   * are given in the <path> element's 'd' attribute).
+   */
+  void ToSVGPathSegEncodedData(float *aData);
+
+  /**
+   * The type of this path segment.
+   */
+  virtual PRUint32 Type() const = 0;
+
+protected:
+
+  /**
+   * Generic ctor for DOMSVGPathSeg objects that are created for an attribute.
+   */
+  DOMSVGPathSeg(DOMSVGPathSegList *aList,
+                PRUint32 aListIndex,
+                PRBool aIsAnimValItem);
+
+  /**
+   * Ctor for creating the objects returned by
+   * SVGPathElement.createSVGPathSegXxx(), which do not initially belong to an
+   * attribute.
+   */
+  DOMSVGPathSeg();
+
+  virtual ~DOMSVGPathSeg() {
+    // 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->ItemAt(mListIndex) = nsnull;
+    }
+  }
+
+  nsSVGElement* Element() {
+    return mList->Element();
+  }
+
+  /**
+   * Get a reference to the internal SVGPathSeg 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.
+   */
+  float* InternalItem();
+
+  virtual float* PtrToMemberArgs() = 0;
+
+#ifdef DEBUG
+  PRBool IndexIsValid();
+#endif
+
+  nsRefPtr<DOMSVGPathSegList> 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:31;
+  PRUint32 mIsAnimValItem:1; // PRUint32 because MSVC won't pack otherwise
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(DOMSVGPathSeg, MOZILLA_DOMSVGPATHSEG_IID)
+
+} // namespace mozilla
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegClosePath();
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegMovetoAbs(float x, float y);
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegMovetoRel(float x, float y);
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegLinetoAbs(float x, float y);
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegLinetoRel(float x, float y);
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegCurvetoCubicAbs(float x, float y,
+                                float x1, float y1,
+                                float x2, float y2);
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegCurvetoCubicRel(float x, float y,
+                                float x1, float y1,
+                                float x2, float y2);
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegCurvetoQuadraticAbs(float x, float y,
+                                    float x1, float y1);
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegCurvetoQuadraticRel(float x, float y,
+                                    float x1, float y1);
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegArcAbs(float x, float y,
+                       float r1, float r2, float angle,
+                       PRBool largeArcFlag, PRBool sweepFlag);
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegArcRel(float x, float y,
+                       float r1, float r2, float angle,
+                       PRBool largeArcFlag, PRBool sweepFlag);
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegLinetoHorizontalAbs(float x);
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegLinetoHorizontalRel(float x);
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegLinetoVerticalAbs(float y);
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegLinetoVerticalRel(float y);
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegCurvetoCubicSmoothAbs(float x, float y,
+                                      float x2, float y2);
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegCurvetoCubicSmoothRel(float x, float y,
+                                      float x2, float y2);
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegCurvetoQuadraticSmoothAbs(float x, float y);
+
+nsIDOMSVGPathSeg*
+NS_NewSVGPathSegCurvetoQuadraticSmoothRel(float x, float y);
+
+#endif // MOZILLA_DOMSVGPATHSEG_H__
new file mode 100644
--- /dev/null
+++ b/content/svg/content/src/DOMSVGPathSegList.cpp
@@ -0,0 +1,489 @@
+/* -*- 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 "DOMSVGPathSegList.h"
+#include "DOMSVGPathSeg.h"
+#include "nsDOMError.h"
+#include "SVGAnimatedPathSegList.h"
+#include "nsCOMPtr.h"
+#include "nsSVGAttrTearoffTable.h"
+
+// See the comment in this file's header.
+
+using namespace mozilla;
+
+static nsSVGAttrTearoffTable<void, DOMSVGPathSegList>
+  sSVGPathSegListTearoffTable;
+
+NS_SVG_VAL_IMPL_CYCLE_COLLECTION(DOMSVGPathSegList, mElement)
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMSVGPathSegList)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMSVGPathSegList)
+
+DOMCI_DATA(SVGPathSegList, DOMSVGPathSegList)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGPathSegList)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMSVGPathSegList)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGPathSegList)
+NS_INTERFACE_MAP_END
+
+
+/* static */ already_AddRefed<DOMSVGPathSegList>
+DOMSVGPathSegList::GetDOMWrapper(void *aList,
+                                 nsSVGElement *aElement,
+                                 PRBool aIsAnimValList)
+{
+  DOMSVGPathSegList *wrapper =
+    sSVGPathSegListTearoffTable.GetTearoff(aList);
+  if (!wrapper) {
+    wrapper = new DOMSVGPathSegList(aElement, aIsAnimValList);
+    sSVGPathSegListTearoffTable.AddTearoff(aList, wrapper);
+  }
+  NS_ADDREF(wrapper);
+  return wrapper;
+}
+
+/* static */ DOMSVGPathSegList*
+DOMSVGPathSegList::GetDOMWrapperIfExists(void *aList)
+{
+  return sSVGPathSegListTearoffTable.GetTearoff(aList);
+}
+
+DOMSVGPathSegList::~DOMSVGPathSegList()
+{
+  // We no longer have any list items, and there are no script references to
+  // us.
+  //
+  // Do NOT use InternalList() here! That's different!
+  void *key = mIsAnimValList ?
+    InternalAList().GetAnimValKey() :
+    InternalAList().GetBaseValKey();
+  sSVGPathSegListTearoffTable.RemoveTearoff(key);
+}
+
+void
+DOMSVGPathSegList::InternalListWillChangeTo(const SVGPathData& 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 just as
+  // much, but we have the additional issue that failing to stay in sync would
+  // mean that - assuming we aren't reading bad memory - we would likely end up
+  // decoding command types from argument floats when looking in our
+  // SVGPathData's data array! Either way, we'll likely then go down
+  // NS_NOTREACHED code paths, or end up reading/setting more bad memory!!
+
+  // The only time that our other DOM list type implementations remove items is
+  // if those items become surplus items due to an attribute change or SMIL
+  // animation sample shortening the list. In general though, they try to keep
+  // their existing DOM items, even when things change. To be consistent, we'd
+  // really like to do the same thing. However, because different types of path
+  // segment correspond to different DOMSVGPathSeg subclasses, the type of
+  // items in our list are generally not the same, which makes this harder for
+  // us. We have to remove DOM segments if their type is not the same as the
+  // type of the new internal segment at their index.
+  //
+  // We also need to sync up mInternalDataIndex, but since we need to loop over
+  // all the items in the new list checking types anyway, that's almost
+  // insignificant in terms of overhead.
+  //
+  // Note that this method is called on every single SMIL animation resample
+  // and we have no way to short circuit the overhead since we don't have a
+  // way to tell if the call is due to a new animation, or a resample of an
+  // existing animation (when the number and type of items would be the same).
+  // (Note that a new animation could start overriding an existing animation at
+  // any time, so checking IsAnimating() wouldn't work.) Because we get called
+  // on every sample, it would not be acceptable alternative to throw away all
+  // our items and let them be recreated lazily, since that would break what
+  // script sees!
+
+  PRUint32 length = mItems.Length();
+  PRUint32 index = 0;
+
+  PRUint32 dataLength = aNewValue.mData.Length();
+  PRUint32 dataIndex = 0; // index into aNewValue's raw data array
+
+  PRUint32 newSegType;
+
+  while (index < length && dataIndex < dataLength) {
+    newSegType = SVGPathSegUtils::DecodeType(aNewValue.mData[dataIndex]);
+    if (ItemAt(index) && ItemAt(index)->Type() != newSegType) {
+      ItemAt(index)->RemovingFromList();
+      ItemAt(index) = nsnull;
+    }
+    // Only after the RemovingFromList() can we touch mInternalDataIndex!
+    mItems[index].mInternalDataIndex = dataIndex;
+    ++index;
+    dataIndex += 1 + SVGPathSegUtils::ArgCountForType(newSegType);
+  }
+
+  NS_ABORT_IF_FALSE((index == length && dataIndex <= dataLength) ||
+                    (index <= length && dataIndex == dataLength),
+                    "very bad - list corruption?");
+
+  if (index < length) {
+    // aNewValue has fewer items than our previous internal counterpart
+
+    PRUint32 newLength = index;
+
+    // Remove excess items from the list:
+    for (; index < length; ++index) {
+      if (ItemAt(index)) {
+        ItemAt(index)->RemovingFromList();
+        ItemAt(index) = nsnull;
+      }
+    }
+
+    // Only now may we truncate mItems
+    mItems.SetLength(newLength);
+
+  } else if (dataIndex < dataLength) {
+    // aNewValue has more items than our previous internal counterpart
+
+    // Sync mItems:
+    while (dataIndex < dataLength) {
+      if (!mItems.AppendElement(ItemProxy(nsnull, dataIndex))) {
+        // OOM
+        Clear();
+        return;
+      }
+      dataIndex += 1 + SVGPathSegUtils::ArgCountForType(SVGPathSegUtils::DecodeType(aNewValue.mData[dataIndex]));
+    }
+  }
+
+  NS_ABORT_IF_FALSE(dataIndex == dataLength, "Serious processing error");
+  NS_ABORT_IF_FALSE(index == length, "Serious counting error");
+}
+
+PRBool
+DOMSVGPathSegList::AttrIsAnimating() const
+{
+  return const_cast<DOMSVGPathSegList*>(this)->InternalAList().IsAnimating();
+}
+
+SVGPathData&
+DOMSVGPathSegList::InternalList()
+{
+  SVGAnimatedPathSegList *alist = mElement->GetAnimPathSegList();
+  return mIsAnimValList && alist->IsAnimating() ? *alist->mAnimVal : alist->mBaseVal;
+}
+
+SVGAnimatedPathSegList&
+DOMSVGPathSegList::InternalAList()
+{
+  NS_ABORT_IF_FALSE(mElement->GetAnimPathSegList(), "Internal error");
+  return *mElement->GetAnimPathSegList();
+}
+
+// ----------------------------------------------------------------------------
+// nsIDOMSVGPathSegList implementation:
+
+NS_IMETHODIMP
+DOMSVGPathSegList::GetNumberOfItems(PRUint32 *aNumberOfItems)
+{
+#ifdef MOZ_SMIL
+  if (IsAnimValList()) {
+    Element()->FlushAnimations();
+  }
+#endif
+  *aNumberOfItems = Length();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DOMSVGPathSegList::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(SVGPathData()); // clears mItems
+
+    if (!AttrIsAnimating()) {
+      // The anim val list is in sync with the base val list
+      DOMSVGPathSegList *animList =
+        GetDOMWrapperIfExists(InternalAList().GetAnimValKey());
+      if (animList) {
+        animList->InternalListWillChangeTo(SVGPathData()); // clears its mItems
+      }
+    }
+
+    InternalList().Clear();
+    Element()->DidChangePathSegList(PR_TRUE);
+#ifdef MOZ_SMIL
+    if (AttrIsAnimating()) {
+      Element()->AnimationNeedsResample();
+    }
+#endif
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DOMSVGPathSegList::Initialize(nsIDOMSVGPathSeg *aNewItem,
+                              nsIDOMSVGPathSeg **_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<DOMSVGPathSeg> domItem = do_QueryInterface(aNewItem);
+  if (!domItem) {
+    return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
+  }
+  if (domItem->HasOwner()) {
+    aNewItem = domItem->Clone();
+  }
+
+  Clear();
+  return InsertItemBefore(aNewItem, 0, _retval);
+}
+
+NS_IMETHODIMP
+DOMSVGPathSegList::GetItem(PRUint32 aIndex,
+                           nsIDOMSVGPathSeg **_retval)
+{
+#ifdef MOZ_SMIL
+  if (IsAnimValList()) {
+    Element()->FlushAnimations();
+  }
+#endif
+  if (aIndex < Length()) {
+    EnsureItemAt(aIndex);
+    NS_ADDREF(*_retval = ItemAt(aIndex));
+    return NS_OK;
+  }
+  *_retval = nsnull;
+  return NS_ERROR_DOM_INDEX_SIZE_ERR;
+}
+
+NS_IMETHODIMP
+DOMSVGPathSegList::InsertItemBefore(nsIDOMSVGPathSeg *aNewItem,
+                                    PRUint32 aIndex,
+                                    nsIDOMSVGPathSeg **_retval)
+{
+  *_retval = nsnull;
+  if (IsAnimValList()) {
+    return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
+  }
+
+  nsCOMPtr<DOMSVGPathSeg> domItem = do_QueryInterface(aNewItem);
+  if (!domItem) {
+    return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
+  }
+  if (domItem->HasOwner()) {
+    domItem = domItem->Clone(); // must do this before changing anything!
+  }
+  PRUint32 internalIndex;
+  if (aIndex < Length()) {
+    internalIndex = mItems[aIndex].mInternalDataIndex;
+  } else {
+    aIndex = Length();
+    internalIndex = InternalList().mData.Length();
+  }
+  PRUint32 argCount = SVGPathSegUtils::ArgCountForType(domItem->Type());
+
+  // Ensure we have enough memory so we can avoid complex error handling below:
+  if (!mItems.SetCapacity(mItems.Length() + 1) ||
+      !InternalList().mData.SetCapacity(InternalList().mData.Length() + 1 + argCount)) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  float segAsRaw[1 + NS_SVG_PATH_SEG_MAX_ARGS];
+  domItem->ToSVGPathSegEncodedData(segAsRaw);
+
+  InternalList().mData.InsertElementsAt(internalIndex, segAsRaw, 1 + argCount);
+  mItems.InsertElementAt(aIndex, ItemProxy(domItem.get(), internalIndex));
+
+  // This MUST come after the insertion into InternalList(), or else under the
+  // insertion into InternalList() 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) {
+    mItems[i].mInternalDataIndex += 1 + argCount;
+    if (ItemAt(i)) {
+      ItemAt(i)->UpdateListIndex(i);
+    }
+  }
+
+  Element()->DidChangePathSegList(PR_TRUE);
+#ifdef MOZ_SMIL
+  if (AttrIsAnimating()) {
+    Element()->AnimationNeedsResample();
+  }
+#endif
+  *_retval = domItem.forget().get();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DOMSVGPathSegList::ReplaceItem(nsIDOMSVGPathSeg *aNewItem,
+                               PRUint32 aIndex,
+                               nsIDOMSVGPathSeg **_retval)
+{
+  *_retval = nsnull;
+  if (IsAnimValList()) {
+    return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
+  }
+
+  nsCOMPtr<DOMSVGPathSeg> 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 = domItem->Clone(); // must do this before changing anything!
+  }
+
+  if (ItemAt(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:
+    ItemAt(aIndex)->RemovingFromList();
+  }
+
+  PRUint32 internalIndex = mItems[aIndex].mInternalDataIndex;
+  PRUint32 oldArgCount = SVGPathSegUtils::ArgCountForType(domItem->Type());
+  PRUint32 newArgCount = SVGPathSegUtils::ArgCountForType(domItem->Type());
+
+  float segAsRaw[1 + NS_SVG_PATH_SEG_MAX_ARGS];
+  domItem->ToSVGPathSegEncodedData(segAsRaw);
+
+  PRBool ok = !!InternalList().mData.ReplaceElementsAt(
+                  internalIndex, 1 + oldArgCount,
+                  segAsRaw, 1 + newArgCount);
+  if (!ok) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+  ItemAt(aIndex) = domItem;
+
+  // This MUST come after the ToSVGPathSegEncodedData call otherwise that call
+  // would end up reading bad data from InternalList()!
+  domItem->InsertingIntoList(this, aIndex, IsAnimValList());
+
+  PRUint32 delta = newArgCount - oldArgCount;
+  if (delta != 0) {
+    for (PRUint32 i = aIndex + 1; i < Length(); ++i) {
+      mItems[i].mInternalDataIndex += delta;
+    }
+  }
+
+  Element()->DidChangePathSegList(PR_TRUE);
+#ifdef MOZ_SMIL
+  if (AttrIsAnimating()) {
+    Element()->AnimationNeedsResample();
+  }
+#endif
+  NS_ADDREF(*_retval = domItem.get());
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DOMSVGPathSegList::RemoveItem(PRUint32 aIndex,
+                              nsIDOMSVGPathSeg **_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:
+  ItemAt(aIndex)->RemovingFromList();
+  NS_ADDREF(*_retval = ItemAt(aIndex));
+
+  PRUint32 internalIndex = mItems[aIndex].mInternalDataIndex;
+  PRUint32 segType = SVGPathSegUtils::DecodeType(InternalList().mData[internalIndex]);
+  PRUint32 argCount = SVGPathSegUtils::ArgCountForType(segType);
+
+  InternalList().mData.RemoveElementsAt(internalIndex, 1 + argCount);
+  mItems.RemoveElementAt(aIndex);
+
+  for (PRUint32 i = aIndex; i < Length(); ++i) {
+    mItems[i].mInternalDataIndex -= 1 + argCount;
+    if (ItemAt(i)) {
+      ItemAt(i)->UpdateListIndex(i);
+    }
+  }
+
+  Element()->DidChangePathSegList(PR_TRUE);
+#ifdef MOZ_SMIL
+  if (AttrIsAnimating()) {
+    Element()->AnimationNeedsResample();
+  }
+#endif
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DOMSVGPathSegList::AppendItem(nsIDOMSVGPathSeg *aNewItem,
+                              nsIDOMSVGPathSeg **_retval)
+{
+  return InsertItemBefore(aNewItem, Length(), _retval);
+}
+
+void
+DOMSVGPathSegList::EnsureItemAt(PRUint32 aIndex)
+{
+  if (!ItemAt(aIndex)) {
+    ItemAt(aIndex) = DOMSVGPathSeg::CreateFor(this, aIndex, IsAnimValList());
+  }
+}
+
new file mode 100644
--- /dev/null
+++ b/content/svg/content/src/DOMSVGPathSegList.h
@@ -0,0 +1,235 @@
+/* -*- 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_DOMSVGPATHSEGLIST_H__
+#define MOZILLA_DOMSVGPATHSEGLIST_H__
+
+#include "nsIDOMSVGPathSegList.h"
+#include "SVGPathData.h"
+#include "SVGPathSegUtils.h"
+#include "nsCOMArray.h"
+#include "nsAutoPtr.h"
+
+class nsSVGElement;
+
+namespace mozilla {
+
+class DOMSVGPathSeg;
+class SVGAnimatedPathSegList;
+
+/**
+ * Class DOMSVGPathSegList
+ *
+ * This class is used to create the DOM tearoff objects that wrap internal
+ * SVGPathData 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 nsIDOMSVGAnimatedPathSegList interface
+ * in SVG, we have no parent DOMSVGAnimatedPathSegList (unlike DOMSVGLengthList
+ * which has a parent DOMSVGAnimatedLengthList class). (There is an
+ * SVGAnimatedPathData 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 DOMSVGAnimatedPathSegList (and is in
+ * DOMSVGAnimatedLengthList) is contained in this class.
+ *
+ * This class is strongly intertwined with DOMSVGPathSeg. Our DOMSVGPathSeg
+ * 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 DOMSVGPathSegList : public nsIDOMSVGPathSegList
+{
+  friend class DOMSVGPathSeg;
+
+public:
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS(DOMSVGPathSegList)
+  NS_DECL_NSIDOMSVGPATHSEGLIST
+
+  /**
+   * Factory method to create and return a DOMSVGPathSegList wrapper
+   * for a given internal SVGPathData object. The factory takes care
+   * of caching the object that it returns so that the same object can be
+   * returned for the given SVGPathData 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 SVGPathData will naturally result in a new
+   * DOMSVGPathSegList being returned.
+   *
+   * It's unfortunate that aList is a void* instead of a typed argument. This
+   * is because the mBaseVal and mAnimVal members of SVGAnimatedPathSegList are
+   * of different types - a plain SVGPathData, and a SVGPathData*. We
+   * use the addresses of these members as the key for the hash table, and
+   * clearly SVGPathData* and a SVGPathData** are not the same type.
+   */
+  static already_AddRefed<DOMSVGPathSegList>
+  GetDOMWrapper(void *aList,
+                nsSVGElement *aElement,
+                PRBool aIsAnimValList);
+
+  /**
+   * This method returns the DOMSVGPathSegList wrapper for an internal
+   * SVGPathData object if it currently has a wrapper. If it does
+   * not, then nsnull is returned.
+   */
+  static DOMSVGPathSegList*
+  GetDOMWrapperIfExists(void *aList);
+
+  /**
+   * This will normally be the same as InternalList().CountItems(), 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<DOMSVGPathSegList*>(this)->InternalList().CountItems(),
+                      "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 SVGPathData& 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.
+   */
+  DOMSVGPathSegList(nsSVGElement *aElement, PRBool aIsAnimValList)
+    : mElement(aElement)
+    , mIsAnimValList(aIsAnimValList)
+  {
+    // This call populates mItems with the same number of items as there are
+    // segments contained 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());
+  }
+
+  ~DOMSVGPathSegList();
+
+  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 SVGPathData.
+   *
+   * 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.
+   */
+  SVGPathData& InternalList();
+
+  SVGAnimatedPathSegList& InternalAList();
+
+  /// Creates an instance of the appropriate DOMSVGPathSeg sub-class for
+  // aIndex, if it doesn't already exist.
+  void EnsureItemAt(PRUint32 aIndex);
+
+  DOMSVGPathSeg*& ItemAt(PRUint32 aIndex) {
+    return mItems[aIndex].mItem;
+  }
+
+  /**
+   * This struct is used in our array of mItems to provide us with somewhere to
+   * store the indexes into the internal SVGPathData of the internal seg data
+   * that our DOMSVGPathSeg items wrap (the internal segment data is or varying
+   * length, so we can't just use the index of our DOMSVGPathSeg items
+   * themselves). The reason that we have this separate struct rather than
+   * just storing the internal indexes in the DOMSVGPathSeg items is because we
+   * want to create the DOMSVGPathSeg items lazily on demand.
+   */
+  struct ItemProxy {
+    ItemProxy(){}
+    ItemProxy(DOMSVGPathSeg *aItem, PRUint32 aInternalDataIndex)
+      : mItem(aItem)
+      , mInternalDataIndex(aInternalDataIndex)
+    {}
+
+    DOMSVGPathSeg *mItem;
+    PRUint32 mInternalDataIndex;
+  };
+
+  // Weak refs to our DOMSVGPathSeg items. The items are friends and take care
+  // of clearing our pointer to them when they die.
+  nsTArray<ItemProxy> mItems;
+
+  // Strong ref to our element to keep it alive. We hold this not only for
+  // ourself, but also for our DOMSVGPathSeg items too.
+  nsRefPtr<nsSVGElement> mElement;
+
+  PRPackedBool mIsAnimValList;
+};
+
+} // namespace mozilla
+
+#endif // MOZILLA_DOMSVGPATHSEGLIST_H__
--- a/content/svg/content/src/Makefile.in
+++ b/content/svg/content/src/Makefile.in
@@ -47,16 +47,18 @@ include $(DEPTH)/config/autoconf.mk
 MODULE		= content
 LIBRARY_NAME	= gkcontentsvg_s
 LIBXUL_LIBRARY	= 1
 
 CPPSRCS		= \
 		DOMSVGAnimatedLengthList.cpp \
 		DOMSVGLength.cpp \
 		DOMSVGLengthList.cpp \
+		DOMSVGPathSeg.cpp \
+		DOMSVGPathSegList.cpp \
 		nsDOMSVGZoomEvent.cpp \
 		nsDOMSVGEvent.cpp \
 		nsSVGAElement.cpp \
 		nsSVGAltGlyphElement.cpp \
 		nsSVGAngle.cpp \
 		nsSVGAnimatedNumberList.cpp \
 		nsSVGAnimatedTransformList.cpp \
 		nsSVGBoolean.cpp \
@@ -85,18 +87,16 @@ CPPSRCS		= \
 		nsSVGMatrix.cpp \
 		nsSVGMetadataElement.cpp \
 		nsSVGNumber.cpp \
 		nsSVGNumber2.cpp \
 		nsSVGNumberList.cpp \
 		nsSVGPathDataParser.cpp \
 		nsSVGPathElement.cpp \
 		nsSVGPathGeometryElement.cpp \
-		nsSVGPathSeg.cpp \
-		nsSVGPathSegList.cpp \
 		nsSVGPatternElement.cpp \
 		nsSVGPoint.cpp \
 		nsSVGPointList.cpp \
 		nsSVGPolyElement.cpp \
 		nsSVGPolygonElement.cpp \
 		nsSVGPolylineElement.cpp \
 		nsSVGPreserveAspectRatio.cpp \
 		nsSVGScriptElement.cpp \
@@ -118,18 +118,21 @@ CPPSRCS		= \
 		nsSVGTitleElement.cpp \
 		nsSVGTransform.cpp \
 		nsSVGTransformList.cpp \
 		nsSVGTransformListParser.cpp \
 		nsSVGUseElement.cpp \
 		nsSVGValue.cpp \
 		nsSVGViewBox.cpp \
 		SVGAnimatedLengthList.cpp \
+		SVGAnimatedPathSegList.cpp \
 		SVGLength.cpp \
 		SVGLengthList.cpp \
+		SVGPathData.cpp \
+		SVGPathSegUtils.cpp \
 		$(NULL)
 
 ifdef MOZ_SMIL
 CPPSRCS += nsSVGAnimateElement.cpp \
            nsSVGAnimateTransformElement.cpp \
            nsSVGAnimateMotionElement.cpp \
            nsSVGAnimationElement.cpp \
            nsSVGMpathElement.cpp \
@@ -137,16 +140,17 @@ CPPSRCS += nsSVGAnimateElement.cpp \
            nsSVGTransformSMILType.cpp \
            nsSVGTransformSMILAttr.cpp \
            SVGLengthListSMILType.cpp \
            SVGMotionSMILType.cpp \
            SVGMotionSMILAttr.cpp \
            SVGMotionSMILAnimationFunction.cpp \
            SVGMotionSMILPathUtils.cpp \
            SVGOrientSMILType.cpp \
+           SVGPathSegListSMILType.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
new file mode 100644
--- /dev/null
+++ b/content/svg/content/src/SVGAnimatedPathSegList.cpp
@@ -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 ***** */
+
+#include "SVGAnimatedPathSegList.h"
+#include "DOMSVGPathSegList.h"
+#include "nsSVGElement.h"
+#include "nsSVGAttrTearoffTable.h"
+#ifdef MOZ_SMIL
+#include "nsSMILValue.h"
+#include "SVGPathSegListSMILType.h"
+#endif // MOZ_SMIL
+
+// See the comments in this file's header!
+
+using namespace mozilla;
+
+nsresult
+SVGAnimatedPathSegList::SetBaseValueString(const nsAString& aValue)
+{
+  SVGPathData newBaseValue;
+
+  // The spec says that the path 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
+  // DOMSVGPathSegList::InternalListWillChangeTo().
+
+  DOMSVGPathSegList *baseValWrapper =
+    DOMSVGPathSegList::GetDOMWrapperIfExists(GetBaseValKey());
+  if (baseValWrapper) {
+    baseValWrapper->InternalListWillChangeTo(newBaseValue);
+  }
+
+  DOMSVGPathSegList *animValWrapper;
+  if (!IsAnimating()) {  // DOM anim val wraps our base val too!
+    animValWrapper = DOMSVGPathSegList::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
+SVGAnimatedPathSegList::ClearBaseValue()
+{
+  // We must send these notifications *before* changing mBaseVal! (See above.)
+
+  DOMSVGPathSegList *baseValWrapper =
+    DOMSVGPathSegList::GetDOMWrapperIfExists(GetBaseValKey());
+  if (baseValWrapper) {
+    baseValWrapper->InternalListWillChangeTo(SVGPathData());
+  }
+
+  if (!IsAnimating()) { // DOM anim val wraps our base val too!
+    DOMSVGPathSegList *animValWrapper =
+      DOMSVGPathSegList::GetDOMWrapperIfExists(GetAnimValKey());
+    if (animValWrapper) {
+      animValWrapper->InternalListWillChangeTo(SVGPathData());
+    }
+  }
+
+  mBaseVal.Clear();
+  // Caller notifies
+}
+
+nsresult
+SVGAnimatedPathSegList::SetAnimValue(const SVGPathData& 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.
+  // Unfortunately it is not possible for us to reliably distinguish between
+  // calls to this method that are setting a new sample for an existing
+  // animation, and calls that are setting the first sample of an animation
+  // that will override an existing animation. In the case of DOMSVGPathSegList
+  // the InternalListWillChangeTo method is not virtually free as it is for the
+  // other DOM list classes, so this is a shame. We'd quite like to be able to
+  // skip the call if possible.
+
+  // We must send these notifications *before* changing mAnimVal! (See above.)
+
+  DOMSVGPathSegList *domWrapper =
+    DOMSVGPathSegList::GetDOMWrapperIfExists(GetAnimValKey());
+  if (domWrapper) {
+    domWrapper->InternalListWillChangeTo(aNewAnimValue);
+  }
+  if (!mAnimVal) {
+    mAnimVal = new SVGPathData();
+  }
+  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);
+  }
+  aElement->DidAnimatePathSegList();
+  return rv;
+}
+
+void
+SVGAnimatedPathSegList::ClearAnimValue(nsSVGElement *aElement)
+{
+  // We must send these notifications *before* changing mAnimVal! (See above.)
+
+  DOMSVGPathSegList *domWrapper =
+    DOMSVGPathSegList::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->DidAnimatePathSegList();
+}
+
+#ifdef MOZ_SMIL
+nsISMILAttr*
+SVGAnimatedPathSegList::ToSMILAttr(nsSVGElement *aElement)
+{
+  return new SMILAnimatedPathSegList(this, aElement);
+}
+
+nsresult
+SVGAnimatedPathSegList::
+  SMILAnimatedPathSegList::ValueFromString(const nsAString& aStr,
+                               const nsISMILAnimationElement* /*aSrcElement*/,
+                               nsSMILValue& aValue,
+                               PRBool& aPreventCachingOfSandwich) const
+{
+  nsSMILValue val(&SVGPathSegListSMILType::sSingleton);
+  SVGPathDataAndOwner *list = static_cast<SVGPathDataAndOwner*>(val.mU.mPtr);
+  nsresult rv = list->SetValueFromString(aStr);
+  if (NS_SUCCEEDED(rv)) {
+    list->SetElement(mElement);
+    aValue.Swap(val);
+  }
+  aPreventCachingOfSandwich = PR_FALSE;
+  return rv;
+}
+
+nsSMILValue
+SVGAnimatedPathSegList::SMILAnimatedPathSegList::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(&SVGPathSegListSMILType::sSingleton);
+  SVGPathDataAndOwner *list = static_cast<SVGPathDataAndOwner*>(tmp.mU.mPtr);
+  nsresult rv = list->CopyFrom(mVal->mBaseVal);
+  if (NS_SUCCEEDED(rv)) {
+    list->SetElement(mElement);
+    val.Swap(tmp);
+  }
+  return val;
+}
+
+nsresult
+SVGAnimatedPathSegList::SMILAnimatedPathSegList::SetAnimValue(const nsSMILValue& aValue)
+{
+  NS_ASSERTION(aValue.mType == &SVGPathSegListSMILType::sSingleton,
+               "Unexpected type to assign animated value");
+  if (aValue.mType == &SVGPathSegListSMILType::sSingleton) {
+    mVal->SetAnimValue(*static_cast<SVGPathDataAndOwner*>(aValue.mU.mPtr),
+                       mElement);
+  }
+  return NS_OK;
+}
+
+void
+SVGAnimatedPathSegList::SMILAnimatedPathSegList::ClearAnimValue()
+{
+  if (mVal->mAnimVal) {
+    mVal->ClearAnimValue(mElement);
+  }
+}
+#endif // MOZ_SMIL
+
new file mode 100644
--- /dev/null
+++ b/content/svg/content/src/SVGAnimatedPathSegList.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_SVGANIMATEDPATHSEGLIST_H__
+#define MOZILLA_SVGANIMATEDPATHSEGLIST_H__
+
+#include "SVGPathData.h"
+
+class nsSVGElement;
+
+#ifdef MOZ_SMIL
+#include "nsISMILAttr.h"
+#endif // MOZ_SMIL
+
+namespace mozilla {
+
+/**
+ * Class SVGAnimatedPathSegList
+ *
+ * Despite the fact that no SVGAnimatedPathSegList 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
+ * SVGAnimatedPathData 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 SVGPathData objects,
+ * which helps ensure that the DOM wrappers for SVGPathData objects' are always
+ * kept in sync. This is vitally important (see the comment in
+ * DOMSVGPathSegList::InternalListWillChangeTo) and frees consumers from having
+ * to know or worry about wrappers (or forget about them!) for the most part.
+ */
+class SVGAnimatedPathSegList
+{
+  // friends so that they can get write access to mBaseVal and mAnimVal
+  friend class DOMSVGPathSeg;
+  friend class DOMSVGPathSegList;
+
+public:
+  SVGAnimatedPathSegList() {}
+
+  /**
+   * Because it's so important that mBaseVal and its DOMSVGPathSegList wrapper
+   * (if any) be kept in sync (see the comment in
+   * DOMSVGPathSegList::InternalListWillChangeTo), this method returns a const
+   * reference. Only our friend classes may get mutable references to mBaseVal.
+   */
+  const SVGPathData& GetBaseValue() const {
+    return mBaseVal;
+  }
+
+  nsresult SetBaseValueString(const nsAString& aValue);
+
+  void ClearBaseValue();
+
+  /**
+   * const! See comment for GetBaseValue!
+   */
+  const SVGPathData& GetAnimValue() const {
+    return mAnimVal ? *mAnimVal : mBaseVal;
+  }
+
+  nsresult SetAnimValue(const SVGPathData& 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="">).
+
+  SVGPathData mBaseVal;
+  nsAutoPtr<SVGPathData> mAnimVal;
+
+#ifdef MOZ_SMIL
+  struct SMILAnimatedPathSegList : public nsISMILAttr
+  {
+  public:
+    SMILAnimatedPathSegList(SVGAnimatedPathSegList* 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.
+    SVGAnimatedPathSegList *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_SVGANIMATEDPATHSEGLIST_H__
--- a/content/svg/content/src/SVGMotionSMILAnimationFunction.cpp
+++ b/content/svg/content/src/SVGMotionSMILAnimationFunction.cpp
@@ -36,17 +36,16 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "SVGMotionSMILAnimationFunction.h"
 #include "nsSMILParserUtils.h"
 #include "nsSVGAngle.h"
 #include "SVGMotionSMILType.h"
 #include "SVGMotionSMILPathUtils.h"
 #include "nsSVGPathDataParser.h"
-#include "nsSVGPathSeg.h"
 #include "nsSVGPathElement.h" // for nsSVGPathList
 #include "nsSVGMpathElement.h"
 
 namespace mozilla {
 
 SVGMotionSMILAnimationFunction::SVGMotionSMILAnimationFunction()
   : mRotateType(eRotateType_Explicit),
     mRotateAngle(0.0f),
@@ -248,92 +247,54 @@ void
 SVGMotionSMILAnimationFunction::
   RebuildPathAndVerticesFromMpathElem(nsSVGMpathElement* aMpathElem)
 {
   mPathSourceType = ePathSourceType_Mpath;
 
   // Use the path that's the target of our chosen <mpath> child.
   nsSVGPathElement* pathElem = aMpathElem->GetReferencedPath();
   if (pathElem) {
-    const nsAttrValue* value = pathElem->GetParsedAttr(nsGkAtoms::d);
-    if (value) {
-      const nsAString& pathSpec = value->GetStringValue();
-      nsresult rv = SetPathVerticesFromPathString(pathSpec);
-      if (NS_SUCCEEDED(rv)) {
+    const SVGPathData &path = pathElem->GetAnimPathSegList()->GetAnimValue();
+    // Path data must contain of at least one path segment (if the path data
+    // doesn't begin with a valid "M", then it's invalid).
+    if (path.Length()) {
+      PRBool ok =
+        path.GetDistancesFromOriginToEndsOfVisibleSegments(&mPathVertices);
+      if (ok && mPathVertices.Length()) {
         mPath = pathElem->GetFlattenedPath(
-          pathElem->PrependLocalTransformTo(gfxMatrix()));
+                  pathElem->PrependLocalTransformTo(gfxMatrix()));
       }
     }
   }
 }
 
 void
 SVGMotionSMILAnimationFunction::RebuildPathAndVerticesFromPathAttr()
 {
   const nsAString& pathSpec = GetAttr(nsGkAtoms::path)->GetStringValue();
   mPathSourceType = ePathSourceType_PathAttr;
 
   // Generate gfxFlattenedPath from |path| attr
-  nsresult rv;
-  nsSVGPathList pathData;
-  nsSVGPathDataParserToInternal pathParser(&pathData);
-  rv = pathParser.Parse(pathSpec);
-  if (NS_FAILED(rv)) {
-    // Parse error.
+  SVGPathData path;
+  nsSVGPathDataParserToInternal pathParser(&path);
+
+  // We ignore any failure returned from Parse() since the SVG spec says to
+  // accept all segments up to the first invalid token. Instead we must
+  // explicitly check that the parse produces at least one path segment (if
+  // the path data doesn't begin with a valid "M", then it's invalid).
+  pathParser.Parse(pathSpec);
+  if (!path.Length()) {
     return;
   }
-  mPath = pathData.GetFlattenedPath(gfxMatrix());
 
-  // Generate list of vertices from |path| attr
-  rv = SetPathVerticesFromPathString(pathSpec);
-
-  if (NS_FAILED(rv)) {
-    // The first parser liked our string, but the second did not. (unexpected,
-    // but possible depending on parser implementations.) Clear path so we
-    // completely (instead of partially) fail.
+  mPath = path.ToFlattenedPath(gfxMatrix());
+  PRBool ok = path.GetDistancesFromOriginToEndsOfVisibleSegments(&mPathVertices);
+  if (!ok || !mPathVertices.Length()) {
     mPath = nsnull;
-    NS_WARNING("nsSVGPathDataParserToInternal successfully parsed path string, but "
-               "nsSVGPathDataParserToDOM did not");
-  }
-}
-
-nsresult
-SVGMotionSMILAnimationFunction::SetPathVerticesFromPathString(const nsAString& aPathSpec)
-{
-  // Parse the string to an array of path segments.
-  nsCOMArray<nsIDOMSVGPathSeg> pathSegments;
-  nsSVGPathDataParserToDOM segmentParser(&pathSegments);
-  nsresult rv = segmentParser.Parse(aPathSpec);
-  if (NS_FAILED(rv)) {
-    return rv;
   }
-
-  // Iterate across the parsed segments to populate our mPathVertices array.
-  PRUint32 numSegments = pathSegments.Count();
-  nsSVGPathSegTraversalState ts;
-  double runningDistTotal = 0.0;
-  for (PRUint32 i = 0; i < numSegments; ++i) {
-    nsSVGPathSeg* segment = static_cast<nsSVGPathSeg*>(pathSegments[i]);
-
-    PRUint16 type = nsIDOMSVGPathSeg::PATHSEG_UNKNOWN;
-    segment->GetPathSegType(&type);
-    if (i == 0 ||
-        (type != nsIDOMSVGPathSeg::PATHSEG_MOVETO_ABS &&
-         type != nsIDOMSVGPathSeg::PATHSEG_MOVETO_REL)) {
-
-      // Increment running length total (note that MoveTo's have 0 length)
-      runningDistTotal += segment->GetLength(&ts);
-
-      // Add an entry for the current point.
-      if (!mPathVertices.AppendElement(runningDistTotal)) {
-        return NS_ERROR_OUT_OF_MEMORY;
-      }
-    }
-  }
-  return NS_OK;
 }
 
 // Helper to regenerate our path representation & its list of vertices
 void
 SVGMotionSMILAnimationFunction::
   RebuildPathAndVertices(const nsIContent* aTargetElement)
 {
   NS_ABORT_IF_FALSE(mIsPathStale, "rebuilding path when it isn't stale");
--- a/content/svg/content/src/SVGMotionSMILAnimationFunction.h
+++ b/content/svg/content/src/SVGMotionSMILAnimationFunction.h
@@ -90,17 +90,16 @@ protected:
   void     CheckKeyPoints();
   nsresult SetKeyPoints(const nsAString& aKeyPoints, nsAttrValue& aResult);
   void     UnsetKeyPoints();
   nsresult SetRotate(const nsAString& aRotate, nsAttrValue& aResult);
   void     UnsetRotate();
 
   // Helpers for GetValues
   void     MarkStaleIfAttributeAffectsPath(nsIAtom* aAttribute);
-  nsresult SetPathVerticesFromPathString(const nsAString& aPathSpec);
   void     RebuildPathAndVertices(const nsIContent* aContextElem);
   void     RebuildPathAndVerticesFromMpathElem(nsSVGMpathElement* aMpathElem);
   void     RebuildPathAndVerticesFromPathAttr();
   void     RebuildPathAndVerticesFromBasicAttrs(const nsIContent* aContextElem);
   PRBool   GenerateValuesForPathAndPoints(gfxFlattenedPath* aPath,
                                           PRBool aIsKeyPoints,
                                           nsTArray<double>& aPointDistances,
                                           nsTArray<nsSMILValue>& aResult);
--- a/content/svg/content/src/SVGMotionSMILType.cpp
+++ b/content/svg/content/src/SVGMotionSMILType.cpp
@@ -39,17 +39,16 @@
 
 #include "SVGMotionSMILType.h"
 #include "nsSMILValue.h"
 #include "nsDebug.h"
 #include "nsSVGTransform.h"
 #include "nsSVGAngle.h"
 #include "nsIDOMSVGAngle.h"
 #include "nsSVGPathElement.h"
-#include "nsSVGPathSeg.h"
 #include "nsIDOMSVGPathSeg.h"
 #include "nsIDOMSVGPathSegList.h"
 #include "nsMathUtils.h"
 #include <math.h>
 
 namespace mozilla {
 
 /*static*/ SVGMotionSMILType SVGMotionSMILType::sSingleton;
new file mode 100644
--- /dev/null
+++ b/content/svg/content/src/SVGPathData.cpp
@@ -0,0 +1,750 @@
+/* -*- 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 "SVGPathData.h"
+#include "SVGAnimatedPathSegList.h"
+#include "SVGPathSegUtils.h"
+#include "nsSVGElement.h"
+#include "nsISVGValueUtils.h"
+#include "nsDOMError.h"
+#include "nsContentUtils.h"
+#include "nsString.h"
+#include "nsSVGUtils.h"
+#include "string.h"
+#include "nsSVGPathDataParser.h"
+#include "nsSVGPathGeometryElement.h" // for nsSVGMark
+#include "gfxPlatform.h"
+#include <stdarg.h>
+
+using namespace mozilla;
+
+nsresult
+SVGPathData::CopyFrom(const SVGPathData& rhs)
+{
+  if (!mData.SetCapacity(rhs.mData.Length())) {
+    // Yes, we do want fallible alloc here
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+  mData = rhs.mData;
+  return NS_OK;
+}
+
+void
+SVGPathData::GetValueAsString(nsAString& aValue) const
+{
+  // we need this function in DidChangePathSegList
+  aValue.Truncate();
+  if (!Length()) {
+    return;
+  }
+  PRUint32 i = 0;
+  for (;;) {
+    nsAutoString segAsString;
+    SVGPathSegUtils::GetValueAsString(&mData[i], segAsString);
+    // We ignore OOM, since it's not useful for us to return an error.
+    aValue.Append(segAsString);
+    i += 1 + SVGPathSegUtils::ArgCountForType(mData[i]);
+    if (i >= mData.Length()) {
+      NS_ABORT_IF_FALSE(i == mData.Length(), "Very, very bad - mData corrupt");
+      return;
+    }
+    aValue.Append(' ');
+  }
+}
+
+nsresult
+SVGPathData::SetValueFromString(const nsAString& aValue)
+{
+  // We don't use a temp variable since the spec says to parse everything up to
+  // the first error. We still return any error though so that callers know if
+  // there's a problem.
+
+  nsSVGPathDataParserToInternal pathParser(this);
+  return pathParser.Parse(aValue);
+}
+
+nsresult
+SVGPathData::AppendSeg(PRUint32 aType, ...)
+{
+  PRUint32 oldLength = mData.Length();
+  PRUint32 newLength = oldLength + 1 + SVGPathSegUtils::ArgCountForType(aType);
+  if (!mData.SetLength(newLength)) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+  mData[oldLength] = SVGPathSegUtils::EncodeType(aType);
+  va_list args;
+  va_start(args, aType);
+  for (PRUint32 i = oldLength + 1; i < newLength; ++i) {
+    // NOTE! 'float' is promoted to 'double' when passed through '...'!
+    mData[i] = float(va_arg(args, double));
+  }
+  va_end(args);
+  return NS_OK;
+}
+
+float
+SVGPathData::GetPathLength() const
+{
+  float length = 0.0;
+  SVGPathTraversalState state;
+
+  PRUint32 i = 0;
+  while (i < mData.Length()) {
+    length += SVGPathSegUtils::GetLength(&mData[i], state);
+    i += 1 + SVGPathSegUtils::ArgCountForType(mData[i]);
+  }
+
+  NS_ABORT_IF_FALSE(i == mData.Length(), "Very, very bad - mData corrupt");
+
+  return length;
+}
+
+#ifdef DEBUG
+PRUint32
+SVGPathData::CountItems() const
+{
+  PRUint32 i = 0, count = 0;
+
+  while (i < mData.Length()) {
+    i += 1 + SVGPathSegUtils::ArgCountForType(mData[i]);
+    count++;
+  }
+
+  NS_ABORT_IF_FALSE(i == mData.Length(), "Very, very bad - mData corrupt");
+
+  return count;
+}
+#endif
+
+PRBool
+SVGPathData::GetSegmentLengths(nsTArray<double> *aLengths) const
+{
+  aLengths->Clear();
+  SVGPathTraversalState state;
+
+  PRUint32 i = 0;
+  while (i < mData.Length()) {
+    if (!aLengths->AppendElement(SVGPathSegUtils::GetLength(&mData[i], state))) {
+      aLengths->Clear();
+      return PR_FALSE;
+    }
+    i += 1 + SVGPathSegUtils::ArgCountForType(mData[i]);
+  }
+
+  NS_ABORT_IF_FALSE(i == mData.Length(), "Very, very bad - mData corrupt");
+
+  return PR_TRUE;
+}
+
+PRBool
+SVGPathData::GetDistancesFromOriginToEndsOfVisibleSegments(nsTArray<double> *aOutput) const
+{
+  double distRunningTotal = 0.0;
+  SVGPathTraversalState state;
+
+  aOutput->Clear();
+
+  PRUint32 i = 0;
+  while (i < mData.Length()) {
+    PRUint32 segType = SVGPathSegUtils::DecodeType(mData[i]);
+
+    // We skip all moveto commands except an initial moveto. See the text 'A
+    // "move to" command does not count as an additional point when dividing up
+    // the duration...':
+    //
+    // http://www.w3.org/TR/SVG11/animate.html#AnimateMotionElement
+    //
+    // This is important in the non-default case of calcMode="linear". In
+    // this case an equal amount of time is spent on each path segment,
+    // except on moveto segments which are jumped over immediately.
+
+    if (i == 0 || (segType != nsIDOMSVGPathSeg::PATHSEG_MOVETO_ABS &&
+                   segType != nsIDOMSVGPathSeg::PATHSEG_MOVETO_REL)) {
+      distRunningTotal += SVGPathSegUtils::GetLength(&mData[i], state);
+      if (!aOutput->AppendElement(distRunningTotal)) {
+        return PR_FALSE;
+      }
+    }
+    i += 1 + SVGPathSegUtils::ArgCountForType(segType);
+  }
+
+  NS_ABORT_IF_FALSE(i == mData.Length(), "Very, very bad - mData corrupt?");
+
+  return PR_TRUE;
+}
+
+PRUint32
+SVGPathData::GetPathSegAtLength(float aDistance) const
+{
+  // TODO [SVGWG issue] get specified what happen if 'aDistance' < 0, or
+  // 'aDistance' > the length of the path, or the seg list is empty.
+  // Return -1? Throwing would better help authors avoid tricky bugs (DOM
+  // could do that if we return -1).
+
+  double distRunningTotal = 0.0;
+  PRUint32 i = 0, segIndex = 0;
+  SVGPathTraversalState state;
+
+  while (i < mData.Length()) {
+    distRunningTotal += SVGPathSegUtils::GetLength(&mData[i], state);
+    if (distRunningTotal >= aDistance) {
+      return segIndex;
+    }
+    i += 1 + SVGPathSegUtils::ArgCountForType(mData[i]);
+    segIndex++;
+  }
+
+  NS_ABORT_IF_FALSE(i == mData.Length(), "Very, very bad - mData corrupt");
+
+  return NS_MAX(0U, segIndex - 1); // -1 because while loop takes us 1 too far
+}
+
+void
+SVGPathData::ConstructPath(gfxContext *aCtx) const
+{
+  PRUint32 segType, prevSegType = nsIDOMSVGPathSeg::PATHSEG_UNKNOWN;
+  gfxPoint pathStart(0.0, 0.0); // start point of [sub]path
+  gfxPoint segEnd(0.0, 0.0);    // end point of previous/current segment
+  gfxPoint cp1, cp2;            // previous bezier's control points
+  gfxPoint tcp1, tcp2;          // temporaries
+
+  // Regarding cp1 and cp2: If the previous segment was a cubic bezier curve,
+  // then cp2 is its second control point. If the previous segment was a
+  // quadratic curve, then cp1 is its (only) control point.
+
+  PRUint32 i = 0;
+  while (i < mData.Length()) {
+    segType = SVGPathSegUtils::DecodeType(mData[i++]);
+
+    switch (segType)
+    {
+    case nsIDOMSVGPathSeg::PATHSEG_CLOSEPATH:
+      segEnd = pathStart;
+      aCtx->ClosePath();
+      break;
+
+    case nsIDOMSVGPathSeg::PATHSEG_MOVETO_ABS:
+      pathStart = segEnd = gfxPoint(mData[i], mData[i+1]);
+      aCtx->MoveTo(segEnd);
+      i += 2;
+      break;
+
+    case nsIDOMSVGPathSeg::PATHSEG_MOVETO_REL:
+      pathStart = segEnd += gfxPoint(mData[i], mData[i+1]);
+      aCtx->MoveTo(segEnd);
+      i += 2;
+      break;
+
+    case nsIDOMSVGPathSeg::PATHSEG_LINETO_ABS:
+      segEnd = gfxPoint(mData[i], mData[i+1]);
+      aCtx->LineTo(segEnd);
+      i += 2;
+      break;
+
+    case nsIDOMSVGPathSeg::PATHSEG_LINETO_REL:
+      segEnd += gfxPoint(mData[i], mData[i+1]);
+      aCtx->LineTo(segEnd);
+      i += 2;
+      break;
+
+    case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS:
+      cp1 = gfxPoint(mData[i], mData[i+1]);
+      cp2 = gfxPoint(mData[i+2], mData[i+3]);
+      segEnd = gfxPoint(mData[i+4], mData[i+5]);
+      aCtx->CurveTo(cp1, cp2, segEnd);
+      i += 6;
+      break;
+
+    case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_REL:
+      cp1 = segEnd + gfxPoint(mData[i], mData[i+1]);
+      cp2 = segEnd + gfxPoint(mData[i+2], mData[i+3]);
+      segEnd += gfxPoint(mData[i+4], mData[i+5]);
+      aCtx->CurveTo(cp1, cp2, segEnd);
+      i += 6;
+      break;
+
+    case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_ABS:
+      cp1 = gfxPoint(mData[i], mData[i+1]);
+      // Convert quadratic curve to cubic curve:
+      tcp1 = segEnd + (cp1 - segEnd) * 2 / 3;
+      segEnd = gfxPoint(mData[i+2], mData[i+3]); // changed before setting tcp2!
+      tcp2 = cp1 + (segEnd - cp1) / 3;
+      aCtx->CurveTo(tcp1, tcp2, segEnd);
+      i += 4;
+      break;
+
+    case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_REL:
+      cp1 = segEnd + gfxPoint(mData[i], mData[i+1]);
+      // Convert quadratic curve to cubic curve:
+      tcp1 = segEnd + (cp1 - segEnd) * 2 / 3;
+      segEnd += gfxPoint(mData[i+2], mData[i+3]); // changed before setting tcp2!
+      tcp2 = cp1 + (segEnd - cp1) / 3;
+      aCtx->CurveTo(tcp1, tcp2, segEnd);
+      i += 4;
+      break;
+
+    case nsIDOMSVGPathSeg::PATHSEG_ARC_ABS:
+    case nsIDOMSVGPathSeg::PATHSEG_ARC_REL:
+    {
+      gfxPoint radii(mData[i], mData[i+1]);
+      gfxPoint start = segEnd;
+      gfxPoint end = gfxPoint(mData[i+5], mData[i+6]);
+      if (segType == nsIDOMSVGPathSeg::PATHSEG_ARC_REL) {
+        end += start;
+      }
+      segEnd = end;
+      if (start != end) {
+        if (radii.x == 0.0f || radii.y == 0.0f) {
+          aCtx->LineTo(end);
+          i += 7;
+          break;
+        }
+        nsSVGArcConverter converter(start, end, radii, mData[i+2],
+                                    mData[i+3] != 0, mData[i+4] != 0);
+        while (converter.GetNextSegment(&cp1, &cp2, &end)) {
+          aCtx->CurveTo(cp1, cp2, end);
+        }
+      }
+      i += 7;
+      break;
+    }
+
+    case nsIDOMSVGPathSeg::PATHSEG_LINETO_HORIZONTAL_ABS:
+      segEnd = gfxPoint(mData[i++], segEnd.y);
+      aCtx->LineTo(segEnd);
+      break;
+
+    case nsIDOMSVGPathSeg::PATHSEG_LINETO_HORIZONTAL_REL:
+      segEnd += gfxPoint(mData[i++], 0.0f);
+      aCtx->LineTo(segEnd);
+      break;
+
+    case nsIDOMSVGPathSeg::PATHSEG_LINETO_VERTICAL_ABS:
+      segEnd = gfxPoint(segEnd.x, mData[i++]);
+      aCtx->LineTo(segEnd);
+      break;
+
+    case nsIDOMSVGPathSeg::PATHSEG_LINETO_VERTICAL_REL:
+      segEnd += gfxPoint(0.0f, mData[i++]);
+      aCtx->LineTo(segEnd);
+      break;
+
+    case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS:
+      cp1 = SVGPathSegUtils::IsCubicType(prevSegType) ? segEnd * 2 - cp2 : segEnd;
+      cp2 = gfxPoint(mData[i],   mData[i+1]);
+      segEnd = gfxPoint(mData[i+2], mData[i+3]);
+      aCtx->CurveTo(cp1, cp2, segEnd);
+      i += 4;
+      break;
+
+    case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_REL:
+      cp1 = SVGPathSegUtils::IsCubicType(prevSegType) ? segEnd * 2 - cp2 : segEnd;
+      cp2 = segEnd + gfxPoint(mData[i], mData[i+1]);
+      segEnd += gfxPoint(mData[i+2], mData[i+3]);
+      aCtx->CurveTo(cp1, cp2, segEnd);
+      i += 4;
+      break;
+
+    case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS:
+      cp1 = SVGPathSegUtils::IsQuadraticType(prevSegType) ? segEnd * 2 - cp1 : segEnd;
+      // Convert quadratic curve to cubic curve:
+      tcp1 = segEnd + (cp1 - segEnd) * 2 / 3;
+      segEnd = gfxPoint(mData[i], mData[i+1]); // changed before setting tcp2!
+      tcp2 = cp1 + (segEnd - cp1) / 3;
+      aCtx->CurveTo(tcp1, tcp2, segEnd);
+      i += 2;
+      break;
+
+    case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL:
+      cp1 = SVGPathSegUtils::IsQuadraticType(prevSegType) ? segEnd * 2 - cp1 : segEnd;
+      // Convert quadratic curve to cubic curve:
+      tcp1 = segEnd + (cp1 - segEnd) * 2 / 3;
+      segEnd = segEnd + gfxPoint(mData[i], mData[i+1]); // changed before setting tcp2!
+      tcp2 = cp1 + (segEnd - cp1) / 3;
+      aCtx->CurveTo(tcp1, tcp2, segEnd);
+      i += 2;
+      break;
+
+    default:
+      NS_NOTREACHED("Bad path segment type");
+      return; // according to spec we'd use everything up to the bad seg anyway
+    }
+    prevSegType = segType;
+  }
+  NS_ABORT_IF_FALSE(i == mData.Length(), "Very, very bad - mData corrupt");
+}
+
+already_AddRefed<gfxFlattenedPath>
+SVGPathData::ToFlattenedPath(const gfxMatrix& aMatrix) const
+{
+  nsRefPtr<gfxContext> ctx =
+    new gfxContext(gfxPlatform::GetPlatform()->ScreenReferenceSurface());
+
+  ctx->SetMatrix(aMatrix);
+  ConstructPath(ctx);
+  ctx->IdentityMatrix();
+
+  return ctx->GetFlattenedPath();
+}
+
+static PRBool IsMoveto(PRUint16 aSegType)
+{
+  return aSegType == nsIDOMSVGPathSeg::PATHSEG_MOVETO_ABS ||
+         aSegType == nsIDOMSVGPathSeg::PATHSEG_MOVETO_REL;
+}
+
+static float AngleOfVector(gfxPoint v)
+{
+  // C99 says about atan2 "A domain error may occur if both arguments are
+  // zero" and "On a domain error, the function returns an implementation-
+  // defined value". In the case of atan2 the implementation-defined value
+  // seems to commonly be zero, but it could just as easily be a NaN value.
+  // We specifically want zero in this case, hence the check:
+
+  return (v != gfxPoint(0.0f, 0.0f)) ? atan2(v.y, v.x) : 0.0f;
+}
+
+// TODO replace callers with calls to AngleOfVector
+static double
+CalcVectorAngle(double ux, double uy, double vx, double vy)
+{
+  double ta = atan2(uy, ux);
+  double tb = atan2(vy, vx);
+  if (tb >= ta)
+    return tb-ta;
+  return 2 * M_PI - (ta-tb);
+}
+
+void
+SVGPathData::GetMarkerPositioningData(nsTArray<nsSVGMark> *aMarks) const
+{
+  // This code should assume that ANY type of segment can appear at ANY index.
+  // It should also assume that segments such as M and Z can appear in weird
+  // places, and repeat multiple times consecutively.
+
+  gfxPoint pathStart, segStart, segEnd;
+  gfxPoint cp1, cp2; // control points for current bezier curve
+  gfxPoint prevCP; // last control point of previous bezier curve
+
+  PRUint16 segType, prevSegType = nsIDOMSVGPathSeg::PATHSEG_UNKNOWN;
+
+  // info on the current [sub]path (reset every M command):
+  gfxPoint pathStartPoint(0, 0);
+  float pathStartAngle = 0;
+
+  float prevSegEndAngle = 0, segStartAngle = 0, segEndAngle = 0;
+
+  PRUint32 i = 0;
+  while (i < mData.Length()) {
+    segType = SVGPathSegUtils::DecodeType(mData[i++]); // advances i to args
+
+    switch (segType) // to find segStartAngle, segEnd and segEndAngle
+    {
+    case nsIDOMSVGPathSeg::PATHSEG_CLOSEPATH:
+      segEnd = pathStart;
+      segStartAngle = segEndAngle = AngleOfVector(segEnd - segStart);
+      break;
+
+    case nsIDOMSVGPathSeg::PATHSEG_MOVETO_ABS:
+    case nsIDOMSVGPathSeg::PATHSEG_MOVETO_REL:
+      if (segType == nsIDOMSVGPathSeg::PATHSEG_MOVETO_ABS) {
+        segEnd = gfxPoint(mData[i], mData[i+1]);
+      } else {
+        segEnd = segStart + gfxPoint(mData[i], mData[i+1]);
+      }
+      pathStart = segEnd;
+      // If authors are going to specify multiple consecutive moveto commands
+      // with markers, me might as well make the angle do something useful:
+      segStartAngle = segEndAngle = AngleOfVector(segEnd - segStart);
+      i += 2;
+      break;
+
+    case nsIDOMSVGPathSeg::PATHSEG_LINETO_ABS:
+    case nsIDOMSVGPathSeg::PATHSEG_LINETO_REL:
+      if (segType == nsIDOMSVGPathSeg::PATHSEG_LINETO_ABS) {
+        segEnd = gfxPoint(mData[i], mData[i+1]);
+      } else {
+        segEnd = segStart + gfxPoint(mData[i], mData[i+1]);
+      }
+      segStartAngle = segEndAngle = AngleOfVector(segEnd - segStart);
+      i += 2;
+      break;
+
+    case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS:
+    case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_REL:
+      if (segType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS) {
+        cp1 = gfxPoint(mData[i],   mData[i+1]);
+        cp2 = gfxPoint(mData[i+2], mData[i+3]);
+        segEnd = gfxPoint(mData[i+4], mData[i+5]);
+      } else {
+        cp1 = segStart + gfxPoint(mData[i],   mData[i+1]);
+        cp2 = segStart + gfxPoint(mData[i+2], mData[i+3]);
+        segEnd = segStart + gfxPoint(mData[i+4], mData[i+5]);
+      }
+      prevCP = cp2;
+      if (cp1 == segStart) {
+        cp1 = cp2;
+      }
+      if (cp2 == segEnd) {
+        cp2 = cp1;
+      }
+      segStartAngle = AngleOfVector(cp1 - segStart);
+      segEndAngle = AngleOfVector(segEnd - cp2);
+      i += 6;
+      break;
+
+    case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_ABS:
+    case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_REL:
+      if (segType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_ABS) {
+        cp1 = gfxPoint(mData[i],   mData[i+1]);
+        segEnd = gfxPoint(mData[i+2], mData[i+3]);
+      } else {
+        cp1 = segStart + gfxPoint(mData[i],   mData[i+1]);
+        segEnd = segStart + gfxPoint(mData[i+2], mData[i+3]);
+      }
+      prevCP = cp1;
+      segStartAngle = AngleOfVector(cp1 - segStart);
+      segEndAngle = AngleOfVector(segEnd - cp1);
+      i += 4;
+      break;
+
+    case nsIDOMSVGPathSeg::PATHSEG_ARC_ABS:
+    case nsIDOMSVGPathSeg::PATHSEG_ARC_REL:
+    {
+      float rx = mData[i];
+      float ry = mData[i+1];
+      float angle = mData[i+2];
+      PRBool largeArcFlag = mData[i+3] != 0.0f;
+      PRBool sweepFlag = mData[i+4] != 0.0f;
+      if (segType == nsIDOMSVGPathSeg::PATHSEG_ARC_ABS) {
+        segEnd = gfxPoint(mData[i+5], mData[i+6]);
+      } else {
+        segEnd = segStart + gfxPoint(mData[i+5], mData[i+6]);
+      }
+
+      // See section F.6 of SVG 1.1 for details on what we're doing here:
+      // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
+
+      if (segStart == segEnd) {
+        // F.6.2 says "If the endpoints (x1, y1) and (x2, y2) are identical,
+        // then this is equivalent to omitting the elliptical arc segment
+        // entirely." We take that very literally here, not adding a mark, and
+        // not even setting any of the 'prev' variables so that it's as if this
+        // arc had never existed; note the difference this will make e.g. if
+        // the arc is proceeded by a bezier curve and followed by a "smooth"
+        // bezier curve of the same degree!
+        i += 7;
+        continue;
+      }
+
+      // Below we have funny interleaving of F.6.6 (Correction of out-of-range
+      // radii) and F.6.5 (Conversion from endpoint to center parameterization)
+      // which is designed to avoid some unnecessary calculations.
+
+      if (rx == 0.0 || ry == 0.0) {
+        // F.6.6 step 1 - straight line or coincidental points
+        segStartAngle = segEndAngle = AngleOfVector(segEnd - segStart);
+        i += 7;
+        break;
+      }
+      rx = fabs(rx); // F.6.6.1
+      ry = fabs(ry);
+
+      // F.6.5.1:
+      angle = angle * M_PI/180.0;
+      float x1p = cos(angle) * (segStart.x - segEnd.x) / 2.0
+                + sin(angle) * (segStart.y - segEnd.y) / 2.0;
+      float y1p = -sin(angle) * (segStart.x - segEnd.x) / 2.0
+                 + cos(angle)  *(segStart.y - segEnd.y) / 2.0;
+
+      // This is the root in F.6.5.2 and the numerator under that root:
+      float root;
+      float numerator = rx*rx*ry*ry - rx*rx*y1p*y1p - ry*ry*x1p*x1p;
+
+      if (numerator < 0.0) {
+        // F.6.6 step 3 - |numerator < 0.0| is equivalent to the result of
+        // F.6.6.2 (lamedh) being greater than one. What we have here is radii
+        // that do not reach between segStart and segEnd, so we need to correct
+        // them.
+        float lamedh = 1.0 - numerator/(rx*rx*ry*ry); // equiv to eqn F.6.6.2
+        float s = sqrt(lamedh);
+        rx *= s;  // F.6.6.3
+        ry *= s;
+        // rx and ry changed, so we have to recompute numerator
+        numerator = rx*rx*ry*ry - rx*rx*y1p*y1p - ry*ry*x1p*x1p;
+        NS_ABORT_IF_FALSE(numerator >= 0,
+                          "F.6.6.3 should prevent this. Will sqrt(-num)!");
+      }
+      root = sqrt(numerator/(rx*rx*y1p*y1p + ry*ry*x1p*x1p));
+      if (largeArcFlag == sweepFlag)
+        root = -root;
+
+      float cxp =  root * rx * y1p / ry;  // F.6.5.2
+      float cyp = -root * ry * x1p / rx;
+
+      float theta, delta;
+      theta = CalcVectorAngle(1.0, 0.0,  (x1p-cxp)/rx, (y1p-cyp)/ry); // F.6.5.5
+      delta  = CalcVectorAngle((x1p-cxp)/rx, (y1p-cyp)/ry,
+                               (-x1p-cxp)/rx, (-y1p-cyp)/ry);         // F.6.5.6
+      if (!sweepFlag && delta > 0)
+        delta -= 2.0 * M_PI;
+      else if (sweepFlag && delta < 0)
+        delta += 2.0 * M_PI;
+
+      float tx1, ty1, tx2, ty2;
+      tx1 = -cos(angle)*rx*sin(theta) - sin(angle)*ry*cos(theta);
+      ty1 = -sin(angle)*rx*sin(theta) + cos(angle)*ry*cos(theta);
+      tx2 = -cos(angle)*rx*sin(theta+delta) - sin(angle)*ry*cos(theta+delta);
+      ty2 = -sin(angle)*rx*sin(theta+delta) + cos(angle)*ry*cos(theta+delta);
+
+      if (delta < 0.0f) {
+        tx1 = -tx1;
+        ty1 = -ty1;
+        tx2 = -tx2;
+        ty2 = -ty2;
+      }
+
+      segStartAngle = atan2(ty1, tx1);
+      segEndAngle = atan2(ty2, tx2);
+      i += 7;
+      break;
+    }
+
+    case nsIDOMSVGPathSeg::PATHSEG_LINETO_HORIZONTAL_ABS:
+    case nsIDOMSVGPathSeg::PATHSEG_LINETO_HORIZONTAL_REL:
+      if (segType == nsIDOMSVGPathSeg::PATHSEG_LINETO_HORIZONTAL_ABS) {
+        segEnd = gfxPoint(mData[i++], segStart.y);
+      } else {
+        segEnd = segStart + gfxPoint(mData[i++], 0.0f);
+      }
+      segStartAngle = segEndAngle = AngleOfVector(segEnd - segStart);
+      break;
+
+    case nsIDOMSVGPathSeg::PATHSEG_LINETO_VERTICAL_ABS:
+    case nsIDOMSVGPathSeg::PATHSEG_LINETO_VERTICAL_REL:
+      if (segType == nsIDOMSVGPathSeg::PATHSEG_LINETO_VERTICAL_ABS) {
+        segEnd = gfxPoint(segStart.x, mData[i++]);
+      } else {
+        segEnd = segStart + gfxPoint(0.0f, mData[i++]);
+      }
+      segStartAngle = segEndAngle = AngleOfVector(segEnd - segStart);
+      break;
+
+    case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS:
+    case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_REL:
+      cp1 = SVGPathSegUtils::IsCubicType(prevSegType) ? segStart * 2 - prevCP : segStart;
+      if (segType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS) {
+        cp2 = gfxPoint(mData[i], mData[i+1]);
+        segEnd = gfxPoint(mData[i+2], mData[i+3]);
+      } else {
+        cp2 = segStart + gfxPoint(mData[i], mData[i+1]);
+        segEnd = segStart + gfxPoint(mData[i+2], mData[i+3]);
+      }
+      prevCP = cp2;
+      if (cp1 == segStart) {
+        cp1 = cp2;
+      }
+      if (cp2 == segEnd) {
+        cp2 = cp1;
+      }
+      segStartAngle = AngleOfVector(cp1 - segStart);
+      segEndAngle = AngleOfVector(segEnd - cp2);
+      i += 4;
+      break;
+
+    case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS:
+    case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL:
+      cp1 = SVGPathSegUtils::IsQuadraticType(prevSegType) ? segStart * 2 - prevCP : segStart;
+      if (segType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_ABS) {
+        segEnd = gfxPoint(mData[i], mData[i+1]);
+      } else {
+        segEnd = segStart + gfxPoint(mData[i], mData[i+1]);
+      }
+      prevCP = cp1;
+      segStartAngle = AngleOfVector(cp1 - segStart);
+      segEndAngle = AngleOfVector(segEnd - cp1);
+      i += 2;
+      break;
+
+    default:
+      // Leave any existing marks in aMarks so we have a visual indication of
+      // when things went wrong.
+      NS_ABORT_IF_FALSE(PR_FALSE, "Unknown segment type - path corruption?");
+      return;
+    }
+
+    // Set the angle of the mark at the start of this segment:
+    if (aMarks->Length()) {
+      nsSVGMark &mark = aMarks->ElementAt(aMarks->Length() - 1);
+      if (!IsMoveto(segType) && IsMoveto(prevSegType)) {
+        // start of new subpath
+        pathStartAngle = mark.angle = segStartAngle;
+      } else if (IsMoveto(segType) && !IsMoveto(prevSegType)) {
+        // end of a subpath
+        if (prevSegType != nsIDOMSVGPathSeg::PATHSEG_CLOSEPATH)
+          mark.angle = prevSegEndAngle;
+      } else {
+        if (!(segType == nsIDOMSVGPathSeg::PATHSEG_CLOSEPATH &&
+              prevSegType == nsIDOMSVGPathSeg::PATHSEG_CLOSEPATH))
+          mark.angle = nsSVGUtils::AngleBisect(prevSegEndAngle, segStartAngle);
+      }
+    }
+
+    // Add the mark at the end of this segment, and set its position:
+    if (!aMarks->AppendElement(nsSVGMark(segEnd.x, segEnd.y, 0))) {
+      aMarks->Clear(); // OOM, so try to free some
+      return;
+    }
+
+    if (segType == nsIDOMSVGPathSeg::PATHSEG_CLOSEPATH &&
+        prevSegType != nsIDOMSVGPathSeg::PATHSEG_CLOSEPATH) {
+      aMarks->ElementAt(aMarks->Length() - 1).angle =
+        //aMarks->ElementAt(pathStartIndex).angle =
+        nsSVGUtils::AngleBisect(segEndAngle, pathStartAngle);
+    }
+
+    prevSegType = segType;
+    prevSegEndAngle = segEndAngle;
+    segStart = segEnd;
+  }
+
+  NS_ABORT_IF_FALSE(i == mData.Length(), "Very, very bad - mData corrupt");
+
+  if (aMarks->Length() &&
+      prevSegType != nsIDOMSVGPathSeg::PATHSEG_CLOSEPATH)
+    aMarks->ElementAt(aMarks->Length() - 1).angle = prevSegEndAngle;
+}
+
new file mode 100644
--- /dev/null
+++ b/content/svg/content/src/SVGPathData.h
@@ -0,0 +1,284 @@
+/* -*- 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_SVGPATHDATA_H__
+#define MOZILLA_SVGPATHDATA_H__
+
+#include "SVGPathSegUtils.h"
+#include "nsTArray.h"
+#include "nsSVGElement.h"
+
+class gfxContext;
+class gfxMatrix;
+class gfxFlattenedPath;
+class nsSVGPathDataParserToInternal;
+struct nsSVGMark;
+
+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 DOMSVGPathSegList.
+ *
+ * This class is not called |class SVGPathSegList| for one very good reason;
+ * this class does not provide a list of "SVGPathSeg" items, it provides an
+ * array of floats into which path segments are encoded. See the paragraphs
+ * that follow for why. Note that the Length() method returns the number of
+ * floats in our array, not the number of encoded segments, and the index
+ * operator indexes floats in the array, not segments. If this class were
+ * called SVGPathSegList the names of these methods would be very misleading.
+ *
+ * The reason this class is designed in this way is because there are many
+ * different types of path segment, each taking a different numbers of
+ * arguments. We want to store the segments in an nsTArray to avoid individual
+ * allocations for each item, but the different size of segments means we can't
+ * have one single segment type for the nsTArray (not without using a space
+ * wasteful union or something similar). Since the internal code does not need
+ * to index into the list (the DOM wrapper does, but it handles that itself)
+ * the obvious solution is to have the items in this class take up variable
+ * width and have the internal code iterate over these lists rather than index
+ * into them.
+ *
+ * Implementing indexing to segments with O(1) performance would require us to
+ * allocate and maintain a separate segment index table (keeping that table in
+ * sync when items are inserted or removed from the list). So long as the
+ * internal code doesn't require indexing to segments, we can avoid that
+ * overhead and additional complexity.
+ *
+ * Segment encoding: the first float in the encoding of a segment contains the
+ * segment's type. The segment's type is encoded to/decoded from this float
+ * using the static methods SVGPathSegUtils::EncodeType(PRUint32)/
+ * SVGPathSegUtils::DecodeType(float). If the path segment type in question
+ * takes any arguments then these follow the first float, and are in the same
+ * order as they are given in a <path> element's 'd' attribute (NOT in the
+ * order of the createSVGPathSegXxx() methods' arguments from the SVG DOM
+ * interface SVGPathElement, which are different...grr). Consumers can use
+ * SVGPathSegUtils::ArgCountForType(type) to determine how many arguments
+ * there are (if any), and thus where the current encoded segment ends, and
+ * where the next segment (if any) begins.
+ */
+class SVGPathData
+{
+  friend class SVGAnimatedPathSegList;
+  friend class DOMSVGPathSegList;
+  friend class DOMSVGPathSeg;
+  friend class ::nsSVGPathDataParserToInternal;
+  // nsSVGPathDataParserToInternal will not keep wrappers in sync, so consumers
+  // are responsible for that!
+
+public:
+
+  SVGPathData(){}
+  ~SVGPathData(){}
+
+  // 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 mData.IsEmpty();
+  }
+
+#ifdef DEBUG
+  /**
+   * This method iterates over the encoded segment data and countes the number
+   * of segments we currently have.
+   */
+  PRUint32 CountItems() const;
+#endif
+
+  /**
+   * Returns the number of *floats* in the encoding array, and NOT the number
+   * of segments encoded in this object. (For that, see CountItems() above.)
+   */
+  PRUint32 Length() const {
+    return mData.Length();
+  }
+
+  const float& operator[](PRUint32 aIndex) const {
+    return mData[aIndex];
+  }
+
+  // Used by nsSMILCompositor to check if the cached base val is out of date
+  PRBool operator==(const SVGPathData& rhs) const {
+    // We use memcmp so that we don't need to worry that the data encoded in
+    // the first float may have the same bit pattern as a NaN.
+    return mData.Length() == rhs.mData.Length() &&
+           memcmp(mData.Elements(), rhs.mData.Elements(),
+                  mData.Length() * sizeof(float)) == 0;
+  }
+
+  PRBool SetCapacity(PRUint32 aSize) {
+    return mData.SetCapacity(aSize);
+  }
+
+  void Compact() {
+    mData.Compact();
+  }
+
+
+  float GetPathLength() const;
+
+  PRUint32 GetPathSegAtLength(float aLength) const;
+
+  void GetMarkerPositioningData(nsTArray<nsSVGMark> *aMarks) const;
+
+  /**
+   * Returns PR_TRUE, except on OOM, in which case returns PR_FALSE.
+   */
+  PRBool GetSegmentLengths(nsTArray<double> *aLengths) const;
+
+  /**
+   * Returns PR_TRUE, except on OOM, in which case returns PR_FALSE.
+   */
+  PRBool GetDistancesFromOriginToEndsOfVisibleSegments(nsTArray<double> *aArray) const;
+
+  already_AddRefed<gfxFlattenedPath>
+  ToFlattenedPath(const gfxMatrix& aMatrix) const;
+
+  void ConstructPath(gfxContext *aCtx) const;
+
+  // 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
+  // SVGAnimatedPathSegList 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 SVGPathData& rhs);
+
+  float& operator[](PRUint32 aIndex) {
+    return mData[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 aLength) {
+    return mData.SetLength(aLength);
+  }
+
+  nsresult SetValueFromString(const nsAString& aValue);
+
+  void Clear() {
+    mData.Clear();
+  }
+
+  // Our DOM wrappers have direct access to our mData, so they directly
+  // manipulate it rather than us implementing:
+  //
+  // * InsertItem(PRUint32 aDataIndex, PRUint32 aType, const float *aArgs);
+  // * ReplaceItem(PRUint32 aDataIndex, PRUint32 aType, const float *aArgs);
+  // * RemoveItem(PRUint32 aDataIndex);
+  // * PRBool AppendItem(PRUint32 aType, const float *aArgs);
+
+  nsresult AppendSeg(PRUint32 aType, ...); // variable number of float args
+
+  nsTArray<float> mData;
+};
+
+
+/**
+ * This SVGPathData subclass is for SVGPathSegListSMILType which needs to
+ * have write access to the lists it works with.
+ *
+ * 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.
+ */
+class SVGPathDataAndOwner : public SVGPathData
+{
+public:
+
+  SVGPathDataAndOwner(nsSVGElement *aElement = nsnull)
+    : mElement(aElement)
+  {}
+
+  void SetElement(nsSVGElement *aElement) {
+    mElement = aElement;
+  }
+
+  nsSVGElement* Element() const {
+    return mElement;
+  }
+
+  nsresult CopyFrom(const SVGPathDataAndOwner& rhs) {
+    mElement = rhs.mElement;
+    return SVGPathData::CopyFrom(rhs);
+  }
+
+  /**
+   * Exposed so that SVGPathData baseVals can be copied to
+   * SVGPathDataAndOwner objects. Note that callers should also call
+   * SetElement() when using this method!
+   */
+  nsresult CopyFrom(const SVGPathData& rhs) {
+    return SVGPathData::CopyFrom(rhs);
+  }
+  const float& operator[](PRUint32 aIndex) const {
+    return SVGPathData::operator[](aIndex);
+  }
+  float& operator[](PRUint32 aIndex) {
+    return SVGPathData::operator[](aIndex);
+  }
+  PRBool SetLength(PRUint32 aNumberOfItems) {
+    return SVGPathData::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_SVGPATHDATA_H__
new file mode 100644
--- /dev/null
+++ b/content/svg/content/src/SVGPathSegListSMILType.cpp
@@ -0,0 +1,242 @@
+/* -*- 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 "SVGPathSegListSMILType.h"
+#include "nsSMILValue.h"
+#include "SVGPathData.h"
+#include <math.h>
+
+using namespace mozilla;
+
+/*static*/ SVGPathSegListSMILType SVGPathSegListSMILType::sSingleton;
+
+//----------------------------------------------------------------------
+// nsISMILType implementation
+
+void
+SVGPathSegListSMILType::Init(nsSMILValue &aValue) const
+{
+  NS_ABORT_IF_FALSE(aValue.IsNull(), "Unexpected value type");
+  aValue.mU.mPtr = new SVGPathDataAndOwner();
+  aValue.mType = this;
+}
+
+void
+SVGPathSegListSMILType::Destroy(nsSMILValue& aValue) const
+{
+  NS_PRECONDITION(aValue.mType == this, "Unexpected SMIL value type");
+  delete static_cast<SVGPathDataAndOwner*>(aValue.mU.mPtr);
+  aValue.mU.mPtr = nsnull;
+  aValue.mType = &nsSMILNullType::sSingleton;
+}
+
+nsresult
+SVGPathSegListSMILType::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 SVGPathDataAndOwner* src =
+    static_cast<const SVGPathDataAndOwner*>(aSrc.mU.mPtr);
+  SVGPathDataAndOwner* dest =
+    static_cast<SVGPathDataAndOwner*>(aDest.mU.mPtr);
+
+  return dest->CopyFrom(*src);
+}
+
+PRBool
+SVGPathSegListSMILType::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 SVGPathDataAndOwner*>(aLeft.mU.mPtr) ==
+         *static_cast<const SVGPathDataAndOwner*>(aRight.mU.mPtr);
+}
+
+nsresult
+SVGPathSegListSMILType::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");
+
+  SVGPathDataAndOwner& dest =
+    *static_cast<SVGPathDataAndOwner*>(aDest.mU.mPtr);
+  const SVGPathDataAndOwner& valueToAdd =
+    *static_cast<const SVGPathDataAndOwner*>(aValueToAdd.mU.mPtr);
+
+  if (dest.Length() != valueToAdd.Length()) {
+    // Allow addition to empty dest:
+    if (dest.Length() == 0) {
+      return dest.CopyFrom(valueToAdd);
+    }
+    // For now we only support animation to a list with the same number of
+    // items (and with the same segment types).
+    // nsSVGUtils::ReportToConsole
+    return NS_ERROR_FAILURE;
+  }
+
+  PRUint32 i = 0;
+  while (i < dest.Length()) {
+    PRUint32 type = SVGPathSegUtils::DecodeType(dest[i]);
+    if (type != SVGPathSegUtils::DecodeType(valueToAdd[i])) {
+      // nsSVGUtils::ReportToConsole - can't yet animate between different
+      // types, although it would make sense to allow animation between
+      // some.
+      return NS_ERROR_FAILURE;
+    }
+    i++;
+    if ((type == nsIDOMSVGPathSeg::PATHSEG_ARC_ABS ||
+         type == nsIDOMSVGPathSeg::PATHSEG_ARC_REL) &&
+        (dest[i+3] != valueToAdd[i+3] || dest[i+4] != valueToAdd[i+4])) {
+      // boolean args largeArcFlag and sweepFlag must be the same
+      return NS_ERROR_FAILURE;
+    }
+    PRUint32 segEnd = i + SVGPathSegUtils::ArgCountForType(type);
+    for (; i < segEnd; ++i) {
+      dest[i] += valueToAdd[i];
+    }
+  }
+
+  NS_ABORT_IF_FALSE(i == dest.Length(), "Very, very bad - path data corrupt");
+
+  // For now we only support pure 'to' animation.
+  // nsSVGUtils::ReportToConsole
+  return NS_OK;
+}
+
+nsresult
+SVGPathSegListSMILType::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");
+
+  // See https://bugzilla.mozilla.org/show_bug.cgi?id=522306#c18
+
+  // nsSVGUtils::ReportToConsole
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+nsresult
+SVGPathSegListSMILType::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 SVGPathDataAndOwner& start =
+    *static_cast<const SVGPathDataAndOwner*>(aStartVal.mU.mPtr);
+  const SVGPathDataAndOwner& end =
+    *static_cast<const SVGPathDataAndOwner*>(aEndVal.mU.mPtr);
+  SVGPathDataAndOwner& result =
+    *static_cast<SVGPathDataAndOwner*>(aResult.mU.mPtr);
+
+  if (start.Length() != end.Length() && start.Length() != 0) {
+    // For now we only support animation to a list with the same number of
+    // items (and with the same segment types).
+    // nsSVGUtils::ReportToConsole
+    return NS_ERROR_FAILURE;
+  }
+
+  if (!result.SetLength(end.Length())) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  PRUint32 i = 0;
+
+  if (start.Length() == 0) { // identity path
+    while (i < end.Length()) {
+      PRUint32 type = SVGPathSegUtils::DecodeType(end[i]);
+      result[i] = end[i];
+      i++;
+      PRUint32 segEnd = i + SVGPathSegUtils::ArgCountForType(type);
+      if ((type == nsIDOMSVGPathSeg::PATHSEG_ARC_ABS ||
+           type == nsIDOMSVGPathSeg::PATHSEG_ARC_REL)) {
+        result[i] = end[i] * aUnitDistance;
+        result[i+1] = end[i+1] * aUnitDistance;
+        result[i+2] = end[i+2] * aUnitDistance;
+        // boolean args largeArcFlag and sweepFlag must be the same
+        result[i+3] = end[i+3];
+        result[i+4] = end[i+4];
+        result[i+5] = end[i+5] * aUnitDistance;
+        result[i+6] = end[i+6] * aUnitDistance;
+        i = segEnd;
+      } else {
+        for (; i < segEnd; ++i) {
+          result[i] = end[i] * aUnitDistance;
+        }
+      }
+    }
+  } else {
+    while (i < end.Length()) {
+      PRUint32 type = SVGPathSegUtils::DecodeType(end[i]);
+      if (type != SVGPathSegUtils::DecodeType(start[i])) {
+        // nsSVGUtils::ReportToConsole - can't yet interpolate between different
+        // types, although it would make sense to allow interpolation between
+        // some.
+        return NS_ERROR_FAILURE;
+      }
+      result[i] = end[i];
+      i++;
+      if ((type == nsIDOMSVGPathSeg::PATHSEG_ARC_ABS ||
+           type == nsIDOMSVGPathSeg::PATHSEG_ARC_REL) &&
+          (start[i+3] != end[i+3] || start[i+4] != end[i+4])) {
+        // boolean args largeArcFlag and sweepFlag must be the same
+        return NS_ERROR_FAILURE;
+      }
+      PRUint32 segEnd = i + SVGPathSegUtils::ArgCountForType(type);
+      for (; i < segEnd; ++i) {
+        result[i] = start[i] + (end[i] - start[i]) * aUnitDistance;
+      }
+    }
+  }
+
+  NS_ABORT_IF_FALSE(i == end.Length(), "Very, very bad - path data corrupt");
+
+  return NS_OK;
+}
+
new file mode 100644
--- /dev/null
+++ b/content/svg/content/src/SVGPathSegListSMILType.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) 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 ***** */
+
+#ifndef MOZILLA_SVGPATHSEGLISTSMILTYPE_H_
+#define MOZILLA_SVGPATHSEGLISTSMILTYPE_H_
+
+#include "nsISMILType.h"
+
+class nsSMILValue;
+
+namespace mozilla {
+
+////////////////////////////////////////////////////////////////////////
+// SVGPathSegListSMILType
+//
+// Operations for animating an SVGPathData.
+//
+class SVGPathSegListSMILType : public nsISMILType
+{
+public:
+  // Singleton for nsSMILValue objects to hold onto.
+  static SVGPathSegListSMILType 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.
+  SVGPathSegListSMILType() {}
+  ~SVGPathSegListSMILType() {}
+};
+
+} // namespace mozilla
+
+#endif // MOZILLA_SVGPATHSEGLISTSMILTYPE_H_
new file mode 100644
--- /dev/null
+++ b/content/svg/content/src/SVGPathSegUtils.cpp
@@ -0,0 +1,461 @@
+/* -*- 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 "SVGPathSegUtils.h"
+#include "nsSVGElement.h"
+#include "nsSVGSVGElement.h"
+#include "nsSVGPathDataParser.h"
+#include "nsString.h"
+#include "nsSVGUtils.h"
+#include "nsContentUtils.h"
+#include "nsTextFormatter.h"
+#include "prdtoa.h"
+#include <limits>
+#include "nsMathUtils.h"
+#include "prtypes.h"
+
+using namespace mozilla;
+
+static const float PATH_SEG_LENGTH_TOLERANCE = 0.0000001f;
+static const PRUint32 MAX_RECURSION = 10;
+
+
+/* static */ void
+SVGPathSegUtils::GetValueAsString(const float *aSeg, nsAString& aValue)
+{
+  // Adding new seg type? Is the formatting below acceptable for the new types?
+  PR_STATIC_ASSERT(NS_SVG_PATH_SEG_MAX_ARGS == 7);
+
+  PRUint32 type = DecodeType(aSeg[0]);
+  PRUnichar typeAsChar = GetPathSegTypeAsLetter(type);
+
+  // Special case arcs:
+  if (type == nsIDOMSVGPathSeg::PATHSEG_ARC_ABS ||
+      type == nsIDOMSVGPathSeg::PATHSEG_ARC_REL) {
+    PRBool largeArcFlag = aSeg[4] != 0.0f;
+    PRBool sweepFlag = aSeg[5] != 0.0f;
+    nsTextFormatter::ssprintf(aValue,
+                              NS_LITERAL_STRING("%c%g,%g %g %d,%d %g,%g").get(),
+                              typeAsChar, aSeg[1], aSeg[2], aSeg[3],
+                              largeArcFlag, sweepFlag, aSeg[6], aSeg[7]);
+  } else {
+
+    switch (ArgCountForType(type)) {
+    case 0:
+      aValue = typeAsChar;
+      break;
+
+    case 1:
+      nsTextFormatter::ssprintf(aValue, NS_LITERAL_STRING("%c%g").get(),
+                                typeAsChar, aSeg[1]);
+      break;
+
+    case 2:
+      nsTextFormatter::ssprintf(aValue, NS_LITERAL_STRING("%c%g,%g").get(),
+                                typeAsChar, aSeg[1], aSeg[2]);
+      break;
+
+    case 4:
+      nsTextFormatter::ssprintf(aValue, NS_LITERAL_STRING("%c%g,%g %g,%g").get(),
+                                typeAsChar, aSeg[1], aSeg[2], aSeg[3], aSeg[4]);
+      break;
+
+    case 6:
+      nsTextFormatter::ssprintf(aValue,
+                                NS_LITERAL_STRING("%c%g,%g %g,%g %g,%g").get(),
+                                typeAsChar, aSeg[1], aSeg[2], aSeg[3], aSeg[4],
+                                aSeg[5], aSeg[6]);
+      break;
+
+    default:
+      NS_ABORT_IF_FALSE(PR_FALSE, "Unknown segment type");
+      aValue = NS_LITERAL_STRING("<unknown-segment-type>").get();
+      return;
+    }
+  }
+  
+  // nsTextFormatter::ssprintf is one of the nsTextFormatter methods that
+  // randomly appends '\0' to its output string, which means that the length
+  // of the output string is one too long. We need to manually remove that '\0'
+  // until nsTextFormatter is fixed.
+  //
+  if (aValue[aValue.Length() - 1] == PRUnichar('\0')) {
+    aValue.SetLength(aValue.Length() - 1);
+  }
+}
+
+
+static float
+CalcDistanceBetweenPoints(const gfxPoint &p1, const gfxPoint &p2)
+{
+  return NS_hypot(p2.x - p1.x, p2.y - p1.y);
+}
+
+
+static void SplitQuadraticBezier(const gfxPoint *curve,
+                                 gfxPoint *left,
+                                 gfxPoint *right)
+{
+  left[0].x = curve[0].x;
+  left[0].y = curve[0].y;
+  right[2].x = curve[2].x;
+  right[2].y = curve[2].y;
+  left[1].x = (curve[0].x + curve[1].x) / 2;
+  left[1].y = (curve[0].y + curve[1].y) / 2;
+  right[1].x = (curve[1].x + curve[2].x) / 2;
+  right[1].y = (curve[1].y + curve[2].y) / 2;
+  left[2].x = right[0].x = (left[1].x + right[1].x) / 2;
+  left[2].y = right[0].y = (left[1].y + right[1].y) / 2;
+}
+
+static void SplitCubicBezier(const gfxPoint *curve,
+                             gfxPoint *left,
+                             gfxPoint *right)
+{
+  gfxPoint tmp;
+  tmp.x = (curve[1].x + curve[2].x) / 4;
+  tmp.y = (curve[1].y + curve[2].y) / 4;
+  left[0].x = curve[0].x;
+  left[0].y = curve[0].y;
+  right[3].x = curve[3].x;
+  right[3].y = curve[3].y;
+  left[1].x = (curve[0].x + curve[1].x) / 2;
+  left[1].y = (curve[0].y + curve[1].y) / 2;
+  right[2].x = (curve[2].x + curve[3].x) / 2;
+  right[2].y = (curve[2].y + curve[3].y) / 2;
+  left[2].x = left[1].x / 2 + tmp.x;
+  left[2].y = left[1].y / 2 + tmp.y;
+  right[1].x = right[2].x / 2 + tmp.x;
+  right[1].y = right[2].y / 2 + tmp.y;
+  left[3].x = right[0].x = (left[2].x + right[1].x) / 2;
+  left[3].y = right[0].y = (left[2].y + right[1].y) / 2;
+}
+
+static gfxFloat CalcBezLengthHelper(gfxPoint *curve, PRUint32 numPts,
+                                    PRUint32 recursion_count,
+                                    void (*split)(const gfxPoint*, gfxPoint*, gfxPoint*))
+{
+  gfxPoint left[4];
+  gfxPoint right[4];
+  gfxFloat length = 0, dist;
+  for (PRUint32 i = 0; i < numPts - 1; i++) {
+    length += CalcDistanceBetweenPoints(curve[i], curve[i+1]);
+  }
+  dist = CalcDistanceBetweenPoints(curve[0], curve[numPts - 1]);
+  if (length - dist > PATH_SEG_LENGTH_TOLERANCE && recursion_count < MAX_RECURSION) {
+    split(curve, left, right);
+    ++recursion_count;
+    return CalcBezLengthHelper(left, numPts, recursion_count, split) +
+           CalcBezLengthHelper(right, numPts, recursion_count, split);
+  }
+  return length;
+}
+
+static inline gfxFloat
+CalcLengthOfCubicBezier(const gfxPoint &pos, const gfxPoint &cp1,
+                        const gfxPoint &cp2, const gfxPoint &to)
+{
+  gfxPoint curve[4] = { pos, cp1, cp2, to };
+  return CalcBezLengthHelper(curve, 4, 0, SplitCubicBezier);
+}
+
+static inline gfxFloat
+CalcLengthOfQuadraticBezier(const gfxPoint &pos, const gfxPoint &cp,
+                            const gfxPoint &to)
+{
+  gfxPoint curve[3] = { pos, cp, to };
+  return CalcBezLengthHelper(curve, 3, 0, SplitQuadraticBezier);
+}
+
+
+static float GetLengthOfClosePath(const float *aArgs, SVGPathTraversalState &aState)
+{
+  float dist = CalcDistanceBetweenPoints(aState.pos, aState.start);
+  aState.pos = aState.cp1 = aState.cp2 = aState.start;
+  return dist;
+}
+
+static float GetLengthOfMovetoAbs(const float *aArgs, SVGPathTraversalState &aState)
+{
+  aState.start = aState.pos = aState.cp1 = aState.cp2 = gfxPoint(aArgs[0], aArgs[1]);
+  return 0.0;
+}
+
+static float GetLengthOfMovetoRel(const float *aArgs, SVGPathTraversalState &aState)
+{
+  // aState.pos must be second from right due to +=
+  aState.start = aState.cp1 = aState.cp2 = aState.pos += gfxPoint(aArgs[0], aArgs[1]);
+  return 0.0;
+}
+
+static float GetLengthOfLinetoAbs(const float *aArgs, SVGPathTraversalState &aState)
+{
+  gfxPoint to(aArgs[0], aArgs[1]);
+  float dist = CalcDistanceBetweenPoints(aState.pos, to);
+  aState.pos = aState.cp1 = aState.cp2 = to;
+  return dist;
+}
+
+static float GetLengthOfLinetoRel(const float *aArgs, SVGPathTraversalState &aState)
+{
+  gfxPoint to = aState.pos + gfxPoint(aArgs[0], aArgs[1]);
+  float dist = CalcDistanceBetweenPoints(aState.pos, to);
+  aState.pos = aState.cp1 = aState.cp2 = to;
+  return dist;
+}
+
+static float
+GetLengthOfLinetoHorizontalAbs(const float *aArgs, SVGPathTraversalState &aState)
+{
+  gfxPoint to(aArgs[0], aState.pos.y);
+  float dist = fabs(to.x - aState.pos.x);
+  aState.pos = aState.cp1 = aState.cp2 = to;
+  return dist;
+}
+
+static float
+GetLengthOfLinetoHorizontalRel(const float *aArgs, SVGPathTraversalState &aState)
+{
+  aState.cp1 = aState.cp2 = aState.pos += gfxPoint(aArgs[0], 0.0);
+  return fabs(aArgs[0]);
+}
+
+static float
+GetLengthOfLinetoVerticalAbs(const float *aArgs, SVGPathTraversalState &aState)
+{
+  gfxPoint to(aState.pos.x, aArgs[0]);
+  float dist = fabs(to.y - aState.pos.y);
+  aState.pos = aState.cp1 = aState.cp2 = to;
+  return dist;
+}
+
+static float
+GetLengthOfLinetoVerticalRel(const float *aArgs, SVGPathTraversalState &aState)
+{
+  aState.cp1 = aState.cp2 = aState.pos += gfxPoint(0.0, aArgs[0]);
+  return fabs(aArgs[0]);
+}
+
+static float GetLengthOfCurvetoCubicAbs(const float *aArgs, SVGPathTraversalState &aState)
+{
+  gfxPoint cp1(aArgs[0], aArgs[1]);
+  gfxPoint cp2(aArgs[2], aArgs[3]);
+  gfxPoint to(aArgs[4], aArgs[5]);
+
+  float dist = (float)CalcLengthOfCubicBezier(aState.pos, cp1, cp2, to);
+
+  aState.cp2 = cp2;
+  aState.pos = aState.cp1 = to;
+
+  return dist;
+}
+
+static float
+GetLengthOfCurvetoCubicSmoothAbs(const float *aArgs, SVGPathTraversalState &aState)
+{
+  gfxPoint cp1 = aState.pos - (aState.cp2 - aState.pos);
+  gfxPoint cp2(aArgs[0], aArgs[1]);
+  gfxPoint to(aArgs[2], aArgs[3]);
+
+  float dist = (float)CalcLengthOfCubicBezier(aState.pos, cp1, cp2, to);
+
+  aState.cp2 = cp2;
+  aState.pos = aState.cp1 = to;
+
+  return dist;
+}
+
+static float
+GetLengthOfCurvetoCubicRel(const float *aArgs, SVGPathTraversalState &aState)
+{
+  gfxPoint cp1 = aState.pos + gfxPoint(aArgs[0], aArgs[1]);
+  gfxPoint cp2 = aState.pos + gfxPoint(aArgs[2], aArgs[3]);
+  gfxPoint to  = aState.pos + gfxPoint(aArgs[4], aArgs[5]);
+
+  float dist = (float)CalcLengthOfCubicBezier(aState.pos, cp1, cp2, to);
+
+  aState.cp2 = cp2;
+  aState.pos = aState.cp1 = to;
+
+  return dist;
+}
+
+static float
+GetLengthOfCurvetoCubicSmoothRel(const float *aArgs, SVGPathTraversalState &aState)
+{
+  gfxPoint cp1 = aState.pos - (aState.cp2 - aState.pos);
+  gfxPoint cp2 = aState.pos + gfxPoint(aArgs[0], aArgs[1]);
+  gfxPoint to  = aState.pos + gfxPoint(aArgs[2], aArgs[3]);
+
+  float dist = (float)CalcLengthOfCubicBezier(aState.pos, cp1, cp2, to);
+
+  aState.cp2 = cp2;
+  aState.pos = aState.cp1 = to;
+
+  return dist;
+}
+
+static float
+GetLengthOfCurvetoQuadraticAbs(const float *aArgs, SVGPathTraversalState &aState)
+{
+  gfxPoint cp(aArgs[0], aArgs[1]);
+  gfxPoint to(aArgs[2], aArgs[3]);
+
+  float dist = (float)CalcLengthOfQuadraticBezier(aState.pos, cp, to);
+
+  aState.cp1 = cp;
+  aState.pos = aState.cp2 = to;
+
+  return dist;
+}
+
+static float
+GetLengthOfCurvetoQuadraticSmoothAbs(const float *aArgs, SVGPathTraversalState &aState)
+{
+  gfxPoint cp = aState.pos - (aState.cp1 - aState.pos);
+  gfxPoint to(aArgs[0], aArgs[1]);
+
+  float dist = (float)CalcLengthOfQuadraticBezier(aState.pos, cp, to);
+
+  aState.cp1 = cp;
+  aState.pos = aState.cp2 = to;
+
+  return dist;
+}
+
+static float
+GetLengthOfCurvetoQuadraticRel(const float *aArgs, SVGPathTraversalState &aState)
+{
+  gfxPoint cp = aState.pos + gfxPoint(aArgs[0], aArgs[1]);
+  gfxPoint to = aState.pos + gfxPoint(aArgs[2], aArgs[3]);
+
+  float dist = (float)CalcLengthOfQuadraticBezier(aState.pos, cp, to);
+
+  aState.cp1 = cp;
+  aState.pos = aState.cp2 = to;
+
+  return dist;
+}
+
+static float
+GetLengthOfCurvetoQuadraticSmoothRel(const float *aArgs, SVGPathTraversalState &aState)
+{
+  gfxPoint cp = aState.pos - (aState.cp1 - aState.pos);
+  gfxPoint to = aState.pos + gfxPoint(aArgs[0], aArgs[1]);
+
+  float dist = (float)CalcLengthOfQuadraticBezier(aState.pos, cp, to);
+
+  aState.cp1 = cp;
+  aState.pos = aState.cp2 = to;
+
+  return dist;
+}
+
+static float
+GetLengthOfArcAbs(const float *aArgs, SVGPathTraversalState &aState)
+{
+  gfxPoint radii(aArgs[0], aArgs[1]);
+  gfxPoint to(aArgs[5], aArgs[6]);
+  gfxPoint bez[4] = { aState.pos, gfxPoint(0,0), gfxPoint(0,0), gfxPoint(0,0) };
+  nsSVGArcConverter converter(aState.pos, to, radii, aArgs[2],
+                              aArgs[3] != 0, aArgs[4] != 0);
+  float dist = 0;
+  while (converter.GetNextSegment(&bez[1], &bez[2], &bez[3]))
+  {
+    dist += CalcBezLengthHelper(bez, 4, 0, SplitCubicBezier);
+    bez[0] = bez[3];
+  }
+  aState.pos = aState.cp1 = aState.cp2 = to;
+  return dist;
+}
+
+static float
+GetLengthOfArcRel(const float *aArgs, SVGPathTraversalState &aState)
+{
+  gfxPoint radii(aArgs[0], aArgs[1]);
+  gfxPoint to = aState.pos + gfxPoint(aArgs[5], aArgs[6]);
+  gfxPoint bez[4] = { aState.pos, gfxPoint(0,0), gfxPoint(0,0), gfxPoint(0,0) };
+  nsSVGArcConverter converter(aState.pos, to, radii, aArgs[2],
+                              aArgs[3] != 0, aArgs[4] != 0);
+  float dist = 0;
+  while (converter.GetNextSegment(&bez[1], &bez[2], &bez[3]))
+  {
+    dist += CalcBezLengthHelper(bez, 4, 0, SplitCubicBezier);
+    bez[0] = bez[3];
+  }
+  aState.pos = aState.cp1 = aState.cp2 = to;
+  return dist;
+}
+
+
+typedef float (*getLengthFunc)(const float*, SVGPathTraversalState&);
+
+/* static */ float
+SVGPathSegUtils::GetLength(const float *seg, SVGPathTraversalState &aState)
+{
+  PRUint32 type = DecodeType(seg[0]);
+
+  static getLengthFunc lengthFuncTable[20] = {
+    nsnull, //  0 == PATHSEG_UNKNOWN
+    GetLengthOfClosePath,
+    GetLengthOfMovetoAbs,
+    GetLengthOfMovetoRel,
+    GetLengthOfLinetoAbs,
+    GetLengthOfLinetoRel,
+    GetLengthOfCurvetoCubicAbs,
+    GetLengthOfCurvetoCubicRel,
+    GetLengthOfCurvetoQuadraticAbs,
+    GetLengthOfCurvetoQuadraticRel,
+    GetLengthOfArcAbs,
+    GetLengthOfArcRel,
+    GetLengthOfLinetoHorizontalAbs,
+    GetLengthOfLinetoHorizontalRel,
+    GetLengthOfLinetoVerticalAbs,
+    GetLengthOfLinetoVerticalRel,
+    GetLengthOfCurvetoCubicSmoothAbs,
+    GetLengthOfCurvetoCubicSmoothRel,
+    GetLengthOfCurvetoQuadraticSmoothAbs,
+    GetLengthOfCurvetoQuadraticSmoothRel
+  };
+
+  NS_ABORT_IF_FALSE(IsValidType(type), "Seg type not recognized");
+
+  NS_ABORT_IF_FALSE(type > 0 && type < NS_ARRAY_LENGTH(lengthFuncTable),
+                    "Seg type not recognized");
+
+  return lengthFuncTable[type](seg + 1, aState);
+}
+
new file mode 100644
--- /dev/null
+++ b/content/svg/content/src/SVGPathSegUtils.h
@@ -0,0 +1,217 @@
+/* -*- 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_SVGPATHSEGUTILS_H__
+#define MOZILLA_SVGPATHSEGUTILS_H__
+
+#include "nsIDOMSVGPathSeg.h"
+#include "nsIContent.h"
+#include "nsAString.h"
+#include "nsContentUtils.h"
+#include "gfxPoint.h"
+
+#define NS_SVG_PATH_SEG_MAX_ARGS 7
+
+namespace mozilla {
+
+/**
+ * Code that works with path segments can use an instance of this class to
+ * store/provide information about the start of the current subpath and the
+ * last path segment (if any).
+ */
+struct SVGPathTraversalState
+{
+  SVGPathTraversalState()
+    : start(0.0, 0.0)
+    , pos(0.0, 0.0)
+    , cp1(0.0, 0.0)
+    , cp2(0.0, 0.0)
+  {}
+
+  gfxPoint start; // start point of current sub path (reset each moveto)
+
+  gfxPoint pos;   // current position (end point of previous segment)
+
+  gfxPoint cp1;   // quadratic control point - if the previous segment was a
+                  // quadratic bezier curve then this is set to the absolute
+                  // position of its control point, otherwise its set to pos
+
+  gfxPoint cp2;   // cubic control point - if the previous segment was a cubic
+                  // bezier curve then this is set to the absolute position of
+                  // its second control point, otherwise it's set to pos
+};
+
+
+/**
+ * This class is just a collection of static methods - it doesn't have any data
+ * members, and it's not possible to create instances of this class. This class
+ * exists purely as a convenient place to gather together a bunch of methods
+ * related to manipulating and answering questions about path segments.
+ * Internally we represent path segments purely as an array of floats. See the
+ * comment documenting SVGPathData for more info on that.
+ *
+ * The DOM wrapper classes for encoded path segments (data contained in
+ * instances of SVGPathData) is DOMSVGPathSeg and its sub-classes. Note that
+ * there are multiple different DOM classes for path segs - one for each of the
+ * 19 SVG 1.1 segment types.
+ */
+class SVGPathSegUtils
+{
+private:
+  SVGPathSegUtils(){} // private to prevent instances
+
+public:
+
+  static void GetValueAsString(const float *aSeg, nsAString& aValue);
+
+  /**
+   * Encode a segment type enum to a float.
+   *
+   * At some point in the future we will likely want to encode other
+   * information into the float, such as whether the command was explicit or
+   * not. For now all this method does is save on int to float runtime
+   * conversion by requiring PRUint32 and float to be of the same size so we
+   * can simply do a bitwise PRUint32<->float copy.
+   */
+  static float EncodeType(PRUint32 aType) {
+    PR_STATIC_ASSERT(sizeof(PRUint32) == sizeof(float));
+    NS_ABORT_IF_FALSE(IsValidType(aType), "Seg type not recognized");
+    return *(reinterpret_cast<float*>(&aType));
+  }
+
+  static PRUint32 DecodeType(float aType) {
+    PR_STATIC_ASSERT(sizeof(PRUint32) == sizeof(float));
+    PRUint32 type = *(reinterpret_cast<PRUint32*>(&aType));
+    NS_ABORT_IF_FALSE(IsValidType(type), "Seg type not recognized");
+    return type;
+  }
+
+  static PRUnichar GetPathSegTypeAsLetter(PRUint32 aType) {
+    NS_ABORT_IF_FALSE(IsValidType(aType), "Seg type not recognized");
+
+    static const PRUnichar table[] = {
+      PRUnichar('x'),  //  0 == PATHSEG_UNKNOWN
+      PRUnichar('z'),  //  1 == PATHSEG_CLOSEPATH
+      PRUnichar('M'),  //  2 == PATHSEG_MOVETO_ABS
+      PRUnichar('m'),  //  3 == PATHSEG_MOVETO_REL
+      PRUnichar('L'),  //  4 == PATHSEG_LINETO_ABS
+      PRUnichar('l'),  //  5 == PATHSEG_LINETO_REL
+      PRUnichar('C'),  //  6 == PATHSEG_CURVETO_CUBIC_ABS
+      PRUnichar('c'),  //  7 == PATHSEG_CURVETO_CUBIC_REL
+      PRUnichar('Q'),  //  8 == PATHSEG_CURVETO_QUADRATIC_ABS
+      PRUnichar('q'),  //  9 == PATHSEG_CURVETO_QUADRATIC_REL
+      PRUnichar('A'),  // 10 == PATHSEG_ARC_ABS
+      PRUnichar('a'),  // 11 == PATHSEG_ARC_REL
+      PRUnichar('H'),  // 12 == PATHSEG_LINETO_HORIZONTAL_ABS
+      PRUnichar('h'),  // 13 == PATHSEG_LINETO_HORIZONTAL_REL
+      PRUnichar('V'),  // 14 == PATHSEG_LINETO_VERTICAL_ABS
+      PRUnichar('v'),  // 15 == PATHSEG_LINETO_VERTICAL_REL
+      PRUnichar('S'),  // 16 == PATHSEG_CURVETO_CUBIC_SMOOTH_ABS
+      PRUnichar('s'),  // 17 == PATHSEG_CURVETO_CUBIC_SMOOTH_REL
+      PRUnichar('T'),  // 18 == PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS
+      PRUnichar('t')   // 19 == PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL
+    };
+
+    return table[aType];
+  }
+
+  static PRUint32 ArgCountForType(PRUint32 aType) {
+    NS_ABORT_IF_FALSE(IsValidType(aType), "Seg type not recognized");
+
+    static const PRUint8 table[] = {
+      0,  //  0 == PATHSEG_UNKNOWN
+      0,  //  1 == PATHSEG_CLOSEPATH
+      2,  //  2 == PATHSEG_MOVETO_ABS
+      2,  //  3 == PATHSEG_MOVETO_REL
+      2,  //  4 == PATHSEG_LINETO_ABS
+      2,  //  5 == PATHSEG_LINETO_REL
+      6,  //  6 == PATHSEG_CURVETO_CUBIC_ABS
+      6,  //  7 == PATHSEG_CURVETO_CUBIC_REL
+      4,  //  8 == PATHSEG_CURVETO_QUADRATIC_ABS
+      4,  //  9 == PATHSEG_CURVETO_QUADRATIC_REL
+      7,  // 10 == PATHSEG_ARC_ABS
+      7,  // 11 == PATHSEG_ARC_REL
+      1,  // 12 == PATHSEG_LINETO_HORIZONTAL_ABS
+      1,  // 13 == PATHSEG_LINETO_HORIZONTAL_REL
+      1,  // 14 == PATHSEG_LINETO_VERTICAL_ABS
+      1,  // 15 == PATHSEG_LINETO_VERTICAL_REL
+      4,  // 16 == PATHSEG_CURVETO_CUBIC_SMOOTH_ABS
+      4,  // 17 == PATHSEG_CURVETO_CUBIC_SMOOTH_REL
+      2,  // 18 == PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS
+      2   // 19 == PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL
+    };
+
+    return table[aType];
+  }
+
+  /**
+   * Convenience so that callers can pass a float containing an encoded type
+   * and have it decoded implicitly.
+   */
+  static PRUint32 ArgCountForType(float aType) {
+    return ArgCountForType(DecodeType(aType));
+  }
+
+  static inline PRBool IsValidType(PRUint32 aType) {
+    return aType >= nsIDOMSVGPathSeg::PATHSEG_CLOSEPATH &&
+           aType <= nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL;
+  }
+
+  static inline PRBool IsCubicType(PRUint32 aType) {
+    return aType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_REL ||
+           aType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS ||
+           aType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_REL ||
+           aType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS;
+  }
+
+  static inline PRBool IsQuadraticType(PRUint32 aType) {
+    return aType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_REL ||
+           aType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_ABS ||
+           aType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL ||
+           aType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS;
+  }
+
+  /**
+   * Returns the user unit length of tracing along the path segment.
+   */
+  static float GetLength(const float *aSeg, SVGPathTraversalState &aState);
+
+  static void ToString(const float *aSeg, nsAString& aValue);
+};
+
+} // namespace mozilla
+
+#endif // MOZILLA_SVGPATHSEGUTILS_H__
--- a/content/svg/content/src/nsSVGAnimateMotionElement.h
+++ b/content/svg/content/src/nsSVGAnimateMotionElement.h
@@ -69,16 +69,21 @@ public:
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
   // nsISMILAnimationElement
   virtual nsSMILAnimationFunction& AnimationFunction();
   virtual PRBool GetTargetAttributeName(PRInt32 *aNamespaceID,
                                         nsIAtom **aLocalName) const;
   virtual nsSMILTargetAttrType GetTargetAttributeType() const;
 
+  // nsSVGElement
+  virtual nsIAtom* GetPathDataAttrName() const {
+    return nsGkAtoms::path;
+  }
+
   // Utility method to let our <mpath> children tell us when they've changed,
   // so we can make sure our mAnimationFunction is marked as having changed.
   void MpathChanged() { mAnimationFunction.MpathChanged(); }
 
   virtual nsXPCClassInfo* GetClassInfo();
 };
 
 #endif // NS_SVGANIMATEMOTIONELEMENT_H_
--- a/content/svg/content/src/nsSVGElement.cpp
+++ b/content/svg/content/src/nsSVGElement.cpp
@@ -70,16 +70,17 @@
 #include "nsSVGNumber2.h"
 #include "nsSVGInteger.h"
 #include "nsSVGAngle.h"
 #include "nsSVGBoolean.h"
 #include "nsSVGEnum.h"
 #include "nsSVGViewBox.h"
 #include "nsSVGString.h"
 #include "SVGAnimatedLengthList.h"
+#include "SVGAnimatedPathSegList.h"
 #include "nsIDOMSVGUnitTypes.h"
 #include "nsIDOMSVGNumberList.h"
 #include "nsIDOMSVGAnimatedNumberList.h"
 #include "nsIDOMSVGPointList.h"
 #include "nsIDOMSVGAnimatedPoints.h"
 #include "nsIDOMSVGTransformList.h"
 #include "nsIDOMSVGAnimTransformList.h"
 #include "nsIDOMSVGAnimatedRect.h"
@@ -174,16 +175,19 @@ nsSVGElement::Init()
   }
 
   LengthListAttributesInfo lengthListInfo = GetLengthListInfo();
 
   for (i = 0; i < lengthListInfo.mLengthListCount; i++) {
     lengthListInfo.Reset(i);
   }
 
+  // No need to reset SVGPathData since the default value in always the same
+  // (an empty list).
+
   StringAttributesInfo stringInfo = GetStringInfo();
 
   for (i = 0; i < stringInfo.mStringCount; i++) {
     stringInfo.Reset(i);
   }
 
   return NS_OK;
 }
@@ -369,16 +373,32 @@ nsSVGElement::ParseAttribute(PRInt32 aNa
           }
           foundMatch = PR_TRUE;
           break;
         }
       }
     }
 
     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
+            // call segList->ClearBaseValue()
+          }
+          foundMatch = PR_TRUE;
+        }
+      }
+    }
+
+    if (!foundMatch) {
       // Check for nsSVGNumber2 attribute
       NumberAttributesInfo numberInfo = GetNumberInfo();
       for (i = 0; i < numberInfo.mNumberCount; i++) {
         if (aAttribute == *numberInfo.mNumberInfo[i].mName) {
           if (i + 1 < numberInfo.mNumberCount &&
               aAttribute == *numberInfo.mNumberInfo[i + 1].mName) {
             rv = ParseNumberOptionalNumber(aValue, i, i + 1);
             if (NS_FAILED(rv)) {
@@ -564,16 +584,28 @@ nsSVGElement::UnsetAttr(PRInt32 aNamespa
           DidChangeLengthList(i, PR_FALSE);
           foundMatch = PR_TRUE;
           break;
         }
       }
     }
 
     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;
+        }
+      }
+    }
+
+    if (!foundMatch) {
       // Check if this is a number attribute going away
       NumberAttributesInfo numInfo = GetNumberInfo();
 
       for (PRUint32 i = 0; i < numInfo.mNumberCount; i++) {
         if (aName == *numInfo.mNumberInfo[i].mName) {
           if (i + 1 < numInfo.mNumberCount &&
               aName == *numInfo.mNumberInfo[i + 1].mName) {
             // found a number-optional-number
@@ -1541,16 +1573,46 @@ nsSVGElement::GetAnimatedLengthList(PRUi
   LengthListAttributesInfo info = GetLengthListInfo();
   if (aAttrEnum < info.mLengthListCount) {
     return &(info.mLengthLists[aAttrEnum]);
   }
   NS_NOTREACHED("Bad attrEnum");
   return nsnull;
 }
 
+
+void
+nsSVGElement::DidChangePathSegList(PRBool aDoSetAttr)
+{
+  NS_ABORT_IF_FALSE(GetPathDataAttrName(), "Changing non-existant 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?");
+
+  nsIFrame* frame = GetPrimaryFrame();
+
+  if (frame) {
+    frame->AttributeChanged(kNameSpaceID_None,
+                            GetPathDataAttrName(),
+                            nsIDOMMutationEvent::MODIFICATION);
+  }
+}
+
 nsSVGElement::NumberAttributesInfo
 nsSVGElement::GetNumberInfo()
 {
   return NumberAttributesInfo(nsnull, nsnull, 0);
 }
 
 void nsSVGElement::NumberAttributesInfo::Reset(PRUint8 aAttrEnum)
 {
@@ -2210,16 +2272,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);
       }
     }
   }
 
+  // PathSegLists:
+  {
+    if (GetPathDataAttrName() == aName) {
+      SVGAnimatedPathSegList *segList = GetAnimPathSegList();
+      if (segList) {
+        return segList->ToSMILAttr(this);
+      }
+    }
+  }
+
   // Mapped attributes:
   if (IsAttributeMapped(aName)) {
     nsCSSProperty prop =
       nsCSSProps::LookupProperty(nsDependentAtomString(aName));
     // Check IsPropertyAnimatable to avoid attributes that...
     //  - map to explicitly unanimatable properties (e.g. 'direction')
     //  - map to unsupported attributes (e.g. 'glyph-orientation-horizontal')
     if (nsSMILCSSProperty::IsPropertyAnimatable(prop)) {
--- a/content/svg/content/src/nsSVGElement.h
+++ b/content/svg/content/src/nsSVGElement.h
@@ -69,29 +69,34 @@ class nsSVGEnum;
 struct nsSVGEnumMapping;
 class nsSVGViewBox;
 class nsSVGPreserveAspectRatio;
 class nsSVGString;
 struct gfxMatrix;
 namespace mozilla {
 class SVGAnimatedLengthList;
 class SVGUserUnitList;
+class SVGAnimatedPathSegList;
 }
 
 typedef nsStyledElement nsSVGElementBase;
 
 class nsSVGElement : public nsSVGElementBase,    // nsIContent
                      public nsISVGValueObserver  // :nsISupportsWeakReference
 {
 protected:
   nsSVGElement(already_AddRefed<nsINodeInfo> aNodeInfo);
   nsresult Init();
   virtual ~nsSVGElement();
 
 public:
+  typedef mozilla::SVGUserUnitList SVGUserUnitList;
+  typedef mozilla::SVGAnimatedLengthList SVGAnimatedLengthList;
+  typedef mozilla::SVGAnimatedPathSegList SVGAnimatedPathSegList;
+
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIContent interface methods
 
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               PRBool aCompileEventHandlers);
@@ -162,47 +167,63 @@ public:
   virtual void DidChangeNumber(PRUint8 aAttrEnum, PRBool aDoSetAttr);
   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 DidChangeLengthList(PRUint8 aAttrEnum, 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 DidAnimateLengthList(PRUint8 aAttrEnum);
+  virtual void DidAnimatePathSegList();
   virtual void DidAnimateTransform();
   virtual void DidAnimateString(PRUint8 aAttrEnum);
 
   void GetAnimatedLengthValues(float *aFirst, ...);
   void GetAnimatedNumberValues(float *aFirst, ...);
   void GetAnimatedIntegerValues(PRInt32 *aFirst, ...);
-  void GetAnimatedLengthListValues(mozilla::SVGUserUnitList *aFirst, ...);
-  mozilla::SVGAnimatedLengthList* GetAnimatedLengthList(PRUint8 aAttrEnum);
+  void GetAnimatedLengthListValues(SVGUserUnitList *aFirst, ...);
+  SVGAnimatedLengthList* GetAnimatedLengthList(PRUint8 aAttrEnum);
+  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;
+  }
 
 #ifdef MOZ_SMIL
   virtual nsISMILAttr* GetAnimatedAttr(PRInt32 aNamespaceID, nsIAtom* aName);
   void AnimationNeedsResample();
   void FlushAnimations();
+#else
+  void AnimationNeedsResample() { /* do nothing */ }
+  void FlushAnimations() { /* do nothing */ }
 #endif
 
   virtual void RecompileScriptEventListeners();
 
   void GetStringBaseValue(PRUint8 aAttrEnum, nsAString& aResult) const;
   void SetStringBaseValue(PRUint8 aAttrEnum, const nsAString& aValue);
 
+  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,
                                 const nsAString& aValue, nsAttrValue& aResult);
   static nsresult ReportAttributeParseFailure(nsIDocument* aDocument,
                                               nsIAtom* aAttribute,
                                               const nsAString& aValue);
@@ -352,21 +373,21 @@ protected:
      * is false. This flag is fed down to SVGLengthListSMILType so it can
      * determine if it can sensibly animate from-to lists of different lengths,
      * which is desirable in the case of dx and dy.
      */
     PRPackedBool mCouldZeroPadList;
   };
 
   struct LengthListAttributesInfo {
-    mozilla::SVGAnimatedLengthList* mLengthLists;
+    SVGAnimatedLengthList* mLengthLists;
     LengthListInfo*        mLengthListInfo;
     PRUint32               mLengthListCount;
 
-    LengthListAttributesInfo(mozilla::SVGAnimatedLengthList *aLengthLists,
+    LengthListAttributesInfo(SVGAnimatedLengthList *aLengthLists,
                              LengthListInfo *aLengthListInfo,
                              PRUint32 aLengthListCount)
       : mLengthLists(aLengthLists)
       , mLengthListInfo(aLengthListInfo)
       , mLengthListCount(aLengthListCount)
     {}
 
     void Reset(PRUint8 aAttrEnum);
--- a/content/svg/content/src/nsSVGPathDataParser.cpp
+++ b/content/svg/content/src/nsSVGPathDataParser.cpp
@@ -33,23 +33,24 @@
  * 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 "nsSVGPathDataParser.h"
 #include "nsSVGDataParser.h"
-#include "nsSVGPathSeg.h"
 #include "nsSVGPathElement.h"
 #include "prdtoa.h"
 #include "nsSVGUtils.h"
 #include <stdlib.h>
 #include <math.h>
 
+using namespace mozilla;
+
 nsresult nsSVGPathDataParser::Match()
 {
   return MatchSvgPath();
 }
 
 //----------------------------------------------------------------------
 
 nsresult nsSVGPathDataParser::MatchCoordPair(float* aX, float* aY)
@@ -861,585 +862,259 @@ PRBool nsSVGPathDataParser::IsTokenEllip
 {
   return IsTokenNonNegativeNumberStarter();
 }
 
 
 //-----------------------------------------------------------------------
 
 
-// ---------------------------------------------------------------
-// nsSVGPathDataParserToInternal
 
-nsresult
-nsSVGPathDataParserToInternal::Parse(const nsAString &aValue)
-{
-  mPathData->Clear();
-  mPx = mPy = mCx = mCy = mStartX = mStartY = 0;
-  mNumCommands = mNumArguments = 0;
-  mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_UNKNOWN;
-
-  nsresult rv = nsSVGPathDataParser::Parse(aValue);
-
-  PathFini();
-
-  return rv;
-}
-
-nsresult
-nsSVGPathDataParserToInternal::StoreMoveTo(PRBool absCoords, float x, float y)
-{
-  if (absCoords) {
-    mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_MOVETO_ABS;
-  } else {
-    x += mPx;
-    y += mPy;
-    mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_MOVETO_REL;
-  }
-  return PathMoveTo(x, y);
-}
-
-nsresult
-nsSVGPathDataParserToInternal::StoreClosePath()
-{
-  mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_CLOSEPATH;
-
-  return PathClose();
-}
-
-nsresult
-nsSVGPathDataParserToInternal::StoreLineTo(PRBool absCoords, float x, float y)
-{
-  if (absCoords) {
-    mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_LINETO_ABS;
-  } else {
-    x += mPx;
-    y += mPy;
-    mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_LINETO_REL;
-  }
-  return PathLineTo(x, y);
-}
-
-nsresult
-nsSVGPathDataParserToInternal::StoreHLineTo(PRBool absCoords, float x)
-{
-  if (absCoords) {
-    mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_LINETO_HORIZONTAL_ABS;
-  } else {
-    x += mPx;
-    mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_LINETO_HORIZONTAL_REL;
-  }
-  return PathLineTo(x, mPy);
-}
-
-nsresult
-nsSVGPathDataParserToInternal::StoreVLineTo(PRBool absCoords, float y)
-{
-  if (absCoords) {
-    mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_LINETO_VERTICAL_ABS;
-  } else {
-    y += mPy;
-    mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_LINETO_VERTICAL_REL;
-  }
-  return PathLineTo(mPx, y);
-}
-
-nsresult
-nsSVGPathDataParserToInternal::StoreCurveTo(PRBool absCoords,
-                                            float x, float y,
-                                            float x1, float y1,
-                                            float x2, float y2)
-{
-  if (absCoords) {
-    mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS;
-  } else {
-    x += mPx;  x1 += mPx;  x2 += mPx;
-    y += mPy;  y1 += mPy;  y2 += mPy;
-    mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_REL;
-  }
-  mCx = x2;
-  mCy = y2;
-  return PathCurveTo(x1, y1, x2, y2, x, y);
-}
-
-nsresult
-nsSVGPathDataParserToInternal::StoreSmoothCurveTo(PRBool absCoords,
-                                                  float x, float y,
-                                                  float x2, float y2)
-{
-  float x1, y1;
-
-  // first controlpoint = reflection last one about current point
-  if (mPrevSeg == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_REL        ||
-      mPrevSeg == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS        ||
-      mPrevSeg == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_REL ||
-      mPrevSeg == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS ) {
-    x1 = 2 * mPx - mCx;
-    y1 = 2 * mPy - mCy;
-  } else {
-    x1 = mPx;
-    y1 = mPy;
-  }
-  if (absCoords) {
-    mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS;
-  } else {
-    x += mPx;
-    x2 += mPx;
-    y += mPy;
-    y2 += mPy;
-    mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_REL;
-  }
-  mCx = x2;
-  mCy = y2;
-  return PathCurveTo(x1, y1, x2, y2, x, y);
-}
-
-nsresult
-nsSVGPathDataParserToInternal::StoreQuadCurveTo(PRBool absCoords,
-                                                float x, float y,
-                                                float x1, float y1)
-{
-  if (absCoords) {
-    mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_ABS;
-  } else {
-    x += mPx;
-    x1 += mPx;
-    y += mPy;
-    y1 += mPy;
-    mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_REL;
-  }
-
-  float x31, y31, x32, y32;
-  // conversion of quadratic bezier curve to cubic bezier curve:
-  x31 = mPx + (x1 - mPx) * 2 / 3;
-  y31 = mPy + (y1 - mPy) * 2 / 3;
-  x32 = x1 + (x - x1) / 3;
-  y32 = y1 + (y - y1) / 3;
-
-  mCx = x1;
-  mCy = y1;
-  return PathCurveTo(x31, y31, x32, y32, x, y);
-}
-
-nsresult
-nsSVGPathDataParserToInternal::StoreSmoothQuadCurveTo(PRBool absCoords,
-                                                      float x, float y)
-{
-  float x1, y1;
-
-  // first controlpoint = reflection last one about current point
-  if (mPrevSeg == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_REL        ||
-      mPrevSeg == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_ABS        ||
-      mPrevSeg == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL ||
-      mPrevSeg == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS ) {
-    x1 = 2 * mPx - mCx;
-    y1 = 2 * mPy - mCy;
-  } else {
-    x1 = mPx;
-    y1 = mPy;
-  }
-  if (absCoords) {
-    mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS;
-  } else {
-    x += mPx;
-    y += mPy;
-    mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL;
-  }
-
-  float x31, y31, x32, y32;
-  // conversion of quadratic bezier curve to cubic bezier curve:
-  x31 = mPx + (x1 - mPx) * 2 / 3;
-  y31 = mPy + (y1 - mPy) * 2 / 3;
-  x32 = x1 + (x - x1) / 3;
-  y32 = y1 + (y - y1) / 3;
-
-  mCx = x1;
-  mCy = y1;
-  return PathCurveTo(x31, y31, x32, y32, x, y);
-}
 
 static double
 CalcVectorAngle(double ux, double uy, double vx, double vy)
 {
   double ta = atan2(uy, ux);
   double tb = atan2(vy, vx);
   if (tb >= ta)
     return tb-ta;
   return 2 * M_PI - (ta-tb);
 }
 
-nsresult
-nsSVGPathDataParserToInternal::ConvertArcToCurves(float x2, float y2,
-                                                  float rx, float ry,
-                                                  float angle,
-                                                  PRBool largeArcFlag,
-                                                  PRBool sweepFlag)
-{
-  float x1=mPx, y1=mPy, x3, y3;
-  // Treat out-of-range parameters as described in
-  // http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
-  
-  // If the endpoints (x1, y1) and (x2, y2) are identical, then this
-  // is equivalent to omitting the elliptical arc segment entirely
-  if (x1 == x2 && y1 == y2) {
-    return NS_OK;
-  }
-  // If rX = 0 or rY = 0 then this arc is treated as a straight line
-  // segment (a "lineto") joining the endpoints.
-  if (rx == 0.0f || ry == 0.0f) {
-    return PathLineTo(x2, y2);
-  }
-  nsSVGArcConverter converter(x1, y1, x2, y2, rx, ry, angle,
-                              largeArcFlag, sweepFlag);
-  
-  while (converter.GetNextSegment(&x1, &y1, &x2, &y2, &x3, &y3)) {
-    // c) draw the cubic bezier:
-    nsresult rv = PathCurveTo(x1, y1, x2, y2, x3, y3);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
 
-  return NS_OK;
-}
-
-nsresult
-nsSVGPathDataParserToInternal::StoreEllipticalArc(PRBool absCoords,
-                                                  float x, float y,
-                                                  float r1, float r2,
-                                                  float angle,
-                                                  PRBool largeArcFlag,
-                                                  PRBool sweepFlag)
-{
-  if (absCoords) {
-    mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_ARC_ABS;
-  } else {
-    x += mPx;
-    y += mPy;
-    mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_ARC_REL;
-  }
-  return ConvertArcToCurves(x, y, r1, r2, angle, largeArcFlag, sweepFlag);
-}
-
-nsresult
-nsSVGPathDataParserToInternal::PathEnsureSpace(PRUint32 aNumArgs)
-{
-  if (!(mNumCommands % 4) &&
-      !mCommands.AppendElement())
-    return NS_ERROR_OUT_OF_MEMORY;
-
-  if (!mArguments.SetLength(mArguments.Length()+aNumArgs))
-    return NS_ERROR_OUT_OF_MEMORY;
-
-  return NS_OK;
-}
-
-void
-nsSVGPathDataParserToInternal::PathAddCommandCode(PRUint8 aCommand)
-{
-  PRUint32 offset = mNumCommands / 4;
-  PRUint32 shift = 2 * (mNumCommands % 4);
-  if (shift == 0) {
-    // make sure we set the byte, to avoid false UMR reports
-    mCommands[offset] = aCommand;
-  } else {
-    mCommands[offset] |= aCommand << shift;
-  }
-  mNumCommands++;
-}
-
-nsresult
-nsSVGPathDataParserToInternal::PathMoveTo(float x, float y)
-{
-  nsresult rv = PathEnsureSpace(2);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  PathAddCommandCode(nsSVGPathList::MOVETO);
-  mArguments[mNumArguments++] = x;
-  mArguments[mNumArguments++] = y;
-
-  mPx = mStartX = x;
-  mPy = mStartY = y;
-
-  return NS_OK;
-}
-
-nsresult
-nsSVGPathDataParserToInternal::PathLineTo(float x, float y)
-{
-  nsresult rv = PathEnsureSpace(2);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  PathAddCommandCode(nsSVGPathList::LINETO);
-  mArguments[mNumArguments++] = x;
-  mArguments[mNumArguments++] = y;
-
-  mPx = x;
-  mPy = y;
-
-  return NS_OK;
-}
-
-nsresult
-nsSVGPathDataParserToInternal::PathCurveTo(float x1, float y1,
-                                           float x2, float y2,
-                                           float x3, float y3)
-{
-  nsresult rv = PathEnsureSpace(6);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  PathAddCommandCode(nsSVGPathList::CURVETO);
-  mArguments[mNumArguments++] = x1;
-  mArguments[mNumArguments++] = y1;
-  mArguments[mNumArguments++] = x2;
-  mArguments[mNumArguments++] = y2;
-  mArguments[mNumArguments++] = x3;
-  mArguments[mNumArguments++] = y3;
-
-  mPx = x3;
-  mPy = y3;
-
-  return NS_OK;
-}
-
-nsresult
-nsSVGPathDataParserToInternal::PathClose()
-{
-  nsresult rv = PathEnsureSpace(0);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  PathAddCommandCode(nsSVGPathList::CLOSEPATH);
-
-  mPx = mStartX;
-  mPy = mStartY;
-
-  return NS_OK;
-}
-
-void
-nsSVGPathDataParserToInternal::PathFini()
-{
-  // We're done adding data to the arrays - copy to a straight array
-  // in mPathData, which allows us to remove the 8-byte overhead per
-  // nsTArray.  For a bonus savings we allocate a single array instead
-  // of two.
-  PRUint32 argArraySize;
-
-  argArraySize = mArguments.Length() * sizeof(float);
-  mPathData->mArguments = (float *)malloc(argArraySize + mCommands.Length());
-  if (!mPathData->mArguments)
-    return;
-
-  memcpy(mPathData->mArguments, mArguments.Elements(), argArraySize);
-  memcpy(mPathData->mArguments + mNumArguments,
-         mCommands.Elements(),
-         mCommands.Length());
-  mPathData->mNumArguments = mNumArguments;
-  mPathData->mNumCommands = mNumCommands;
-}
-
-// ---------------------------------------------------------------
-// nsSVGPathDataParserToDOM
-
-nsresult
-nsSVGPathDataParserToDOM::AppendSegment(nsIDOMSVGPathSeg* seg)
-{
-  NS_ENSURE_TRUE(seg, NS_ERROR_OUT_OF_MEMORY);
-  mData->AppendObject(seg);
-  return NS_OK;
-}
-
-
-nsresult
-nsSVGPathDataParserToDOM::StoreMoveTo(PRBool absCoords, float x, float y)
-{
-  return AppendSegment(
-    absCoords ? NS_NewSVGPathSegMovetoAbs(x, y)
-              : NS_NewSVGPathSegMovetoRel(x, y));
-}
-
-nsresult
-nsSVGPathDataParserToDOM::StoreClosePath()
-{
-  return AppendSegment(NS_NewSVGPathSegClosePath());
-}
-
-nsresult
-nsSVGPathDataParserToDOM::StoreLineTo(PRBool absCoords, float x, float y)
-{
-  return AppendSegment(
-    absCoords ? NS_NewSVGPathSegLinetoAbs(x, y)
-              : NS_NewSVGPathSegLinetoRel(x, y));
-}
-
-nsresult
-nsSVGPathDataParserToDOM::StoreHLineTo(PRBool absCoords, float x)
-{
-  return AppendSegment(
-    absCoords ? NS_NewSVGPathSegLinetoHorizontalAbs(x)
-              : NS_NewSVGPathSegLinetoHorizontalRel(x));
-}
-
-nsresult
-nsSVGPathDataParserToDOM::StoreVLineTo(PRBool absCoords, float y)
-{
-  return AppendSegment(
-    absCoords ? NS_NewSVGPathSegLinetoVerticalAbs(y)
-              : NS_NewSVGPathSegLinetoVerticalRel(y));
-}
-
-nsresult
-nsSVGPathDataParserToDOM::StoreCurveTo(PRBool absCoords,
-                                       float x, float y,
-                                       float x1, float y1,
-                                       float x2, float y2)
-{
-  return AppendSegment(
-    absCoords ? NS_NewSVGPathSegCurvetoCubicAbs(x, y, x1, y1, x2, y2)
-              : NS_NewSVGPathSegCurvetoCubicRel(x, y, x1, y1, x2, y2));
-}
-
-nsresult
-nsSVGPathDataParserToDOM::StoreSmoothCurveTo(PRBool absCoords,
-                                             float x, float y,
-                                             float x2, float y2)
-{
-  return AppendSegment(
-    absCoords ? NS_NewSVGPathSegCurvetoCubicSmoothAbs(x, y, x2, y2)
-              : NS_NewSVGPathSegCurvetoCubicSmoothRel(x, y, x2, y2));
-}
-
-nsresult
-nsSVGPathDataParserToDOM::StoreQuadCurveTo(PRBool absCoords,
-                                           float x, float y,
-                                           float x1, float y1)
-{
-  return AppendSegment(
-    absCoords ? NS_NewSVGPathSegCurvetoQuadraticAbs(x, y, x1, y1)
-              : NS_NewSVGPathSegCurvetoQuadraticRel(x, y, x1, y1));
-}
-
-nsresult
-nsSVGPathDataParserToDOM::StoreSmoothQuadCurveTo(PRBool absCoords,
-                                                 float x, float y)
-{
-  return AppendSegment(
-    absCoords ? NS_NewSVGPathSegCurvetoQuadraticSmoothAbs(x, y)
-              : NS_NewSVGPathSegCurvetoQuadraticSmoothRel(x, y));
-}
-
-nsresult
-nsSVGPathDataParserToDOM::StoreEllipticalArc(PRBool absCoords,
-                                             float x, float y,
-                                             float r1, float r2,
-                                             float angle,
-                                             PRBool largeArcFlag,
-                                             PRBool sweepFlag)
-{
-  return AppendSegment(
-    absCoords ? NS_NewSVGPathSegArcAbs(x, y, r1, r2, angle, 
-                                       largeArcFlag, sweepFlag)
-              : NS_NewSVGPathSegArcRel(x, y, r1, r2, angle,
-                                       largeArcFlag, sweepFlag));
-}
-
-nsSVGArcConverter::nsSVGArcConverter(float x1, float y1,
-                                     float x2, float y2,
-                                     float rx, float ry,
-                                     float angle,
+nsSVGArcConverter::nsSVGArcConverter(const gfxPoint &from,
+                                     const gfxPoint &to,
+                                     const gfxPoint &radii,
+                                     double angle,
                                      PRBool largeArcFlag,
                                      PRBool sweepFlag)
 {
   const double radPerDeg = M_PI/180.0;
 
-  // If rX or rY have negative signs, these are dropped; the absolute
-  // value is used instead.
-  mRx = fabs(rx);
-  mRy = fabs(ry);
-
   // Convert to center parameterization as shown in
   // http://www.w3.org/TR/SVG/implnote.html
+  mRx = fabs(radii.x);
+  mRy = fabs(radii.y);
+
   mSinPhi = sin(angle*radPerDeg);
   mCosPhi = cos(angle*radPerDeg);
 
-  double x1dash =  mCosPhi * (x1-x2)/2.0 + mSinPhi * (y1-y2)/2.0;
-  double y1dash = -mSinPhi * (x1-x2)/2.0 + mCosPhi * (y1-y2)/2.0;
+  double x1dash =  mCosPhi * (from.x-to.x)/2.0 + mSinPhi * (from.y-to.y)/2.0;
+  double y1dash = -mSinPhi * (from.x-to.x)/2.0 + mCosPhi * (from.y-to.y)/2.0;
 
   double root;
   double numerator = mRx*mRx*mRy*mRy - mRx*mRx*y1dash*y1dash -
                      mRy*mRy*x1dash*x1dash;
 
   if (numerator < 0.0) {
     //  If mRx , mRy and are such that there is no solution (basically,
-    //  the ellipse is not big enough to reach from (x1, y1) to (x2,
-    //  y2)) then the ellipse is scaled up uniformly until there is
+    //  the ellipse is not big enough to reach from 'from' to 'to'
+    //  then the ellipse is scaled up uniformly until there is
     //  exactly one solution (until the ellipse is just big enough).
 
     // -> find factor s, such that numerator' with mRx'=s*mRx and
     //    mRy'=s*mRy becomes 0 :
-    float s = (float)sqrt(1.0 - numerator/(mRx*mRx*mRy*mRy));
+    double s = sqrt(1.0 - numerator/(mRx*mRx*mRy*mRy));
 
     mRx *= s;
     mRy *= s;
     root = 0.0;
 
   }
   else {
     root = (largeArcFlag == sweepFlag ? -1.0 : 1.0) *
       sqrt( numerator/(mRx*mRx*y1dash*y1dash + mRy*mRy*x1dash*x1dash) );
   }
 
   double cxdash = root*mRx*y1dash/mRy;
   double cydash = -root*mRy*x1dash/mRx;
 
-  mCx = mCosPhi * cxdash - mSinPhi * cydash + (x1+x2)/2.0;
-  mCy = mSinPhi * cxdash + mCosPhi * cydash + (y1+y2)/2.0;
+  mC.x = mCosPhi * cxdash - mSinPhi * cydash + (from.x+to.x)/2.0;
+  mC.y = mSinPhi * cxdash + mCosPhi * cydash + (from.y+to.y)/2.0;
   mTheta = CalcVectorAngle(1.0, 0.0, (x1dash-cxdash)/mRx, (y1dash-cydash)/mRy);
   double dtheta = CalcVectorAngle((x1dash-cxdash)/mRx, (y1dash-cydash)/mRy,
                                   (-x1dash-cxdash)/mRx, (-y1dash-cydash)/mRy);
   if (!sweepFlag && dtheta>0)
     dtheta -= 2.0*M_PI;
   else if (sweepFlag && dtheta<0)
     dtheta += 2.0*M_PI;
 
   // Convert into cubic bezier segments <= 90deg
   mNumSegs = static_cast<int>(ceil(fabs(dtheta/(M_PI/2.0))));
   mDelta = dtheta/mNumSegs;
   mT = 8.0/3.0 * sin(mDelta/4.0) * sin(mDelta/4.0) / sin(mDelta/2.0);
 
-  mX1 = x1;
-  mY1 = y1;
+  mFrom = from;
   mSegIndex = 0;
 }
 
 PRBool
-nsSVGArcConverter::GetNextSegment(float *x1, float *y1,
-                                  float *x2, float *y2,
-                                  float *x3, float *y3)
+nsSVGArcConverter::GetNextSegment(gfxPoint *cp1, gfxPoint *cp2, gfxPoint *to)
 {
   if (mSegIndex == mNumSegs) {
-     return PR_FALSE;
+    return PR_FALSE;
   }
   
-  float cosTheta1 = cos(mTheta);
-  float sinTheta1 = sin(mTheta);
-  float theta2 = mTheta + mDelta;
-  float cosTheta2 = cos(theta2);
-  float sinTheta2 = sin(theta2);
+  double cosTheta1 = cos(mTheta);
+  double sinTheta1 = sin(mTheta);
+  double theta2 = mTheta + mDelta;
+  double cosTheta2 = cos(theta2);
+  double sinTheta2 = sin(theta2);
 
   // a) calculate endpoint of the segment:
-  *x3 = mCosPhi * mRx*cosTheta2 - mSinPhi * mRy*sinTheta2 + mCx;
-  *y3 = mSinPhi * mRx*cosTheta2 + mCosPhi * mRy*sinTheta2 + mCy;
+  to->x = mCosPhi * mRx*cosTheta2 - mSinPhi * mRy*sinTheta2 + mC.x;
+  to->y = mSinPhi * mRx*cosTheta2 + mCosPhi * mRy*sinTheta2 + mC.y;
 
   // b) calculate gradients at start/end points of segment:
-  *x1 = mX1 + mT * ( - mCosPhi * mRx*sinTheta1 - mSinPhi * mRy*cosTheta1);
-  *y1 = mY1 + mT * ( - mSinPhi * mRx*sinTheta1 + mCosPhi * mRy*cosTheta1);
+  cp1->x = mFrom.x + mT * ( - mCosPhi * mRx*sinTheta1 - mSinPhi * mRy*cosTheta1);
+  cp1->y = mFrom.y + mT * ( - mSinPhi * mRx*sinTheta1 + mCosPhi * mRy*cosTheta1);
 
-  *x2 = *x3 + mT * ( mCosPhi * mRx*sinTheta2 + mSinPhi * mRy*cosTheta2);
-  *y2 = *y3 + mT * ( mSinPhi * mRx*sinTheta2 - mCosPhi * mRy*cosTheta2);
+  cp2->x = to->x + mT * ( mCosPhi * mRx*sinTheta2 + mSinPhi * mRy*cosTheta2);
+  cp2->y = to->y + mT * ( mSinPhi * mRx*sinTheta2 - mCosPhi * mRy*cosTheta2);
 
   // do next segment
   mTheta = theta2;
-  mX1 = *x3;
-  mY1 = *y3;
+  mFrom = *to;
   ++mSegIndex;
 
   return PR_TRUE;
 }
 
+
+// ---------------------------------------------------------------
+// nsSVGPathDataParserToInternal
+
+nsresult
+nsSVGPathDataParserToInternal::Parse(const nsAString &aValue)
+{
+  mPathSegList->Clear();
+  return nsSVGPathDataParser::Parse(aValue);
+}
+
+nsresult
+nsSVGPathDataParserToInternal::StoreMoveTo(PRBool absCoords, float x, float y)
+{
+  // Because our IDL compiler doesn't know any better, each seg type constant
+  // in nsIDOMSVGPathSeg is in a separate enum. This results in "warning:
+  // enumeral mismatch in conditional expression" under GCC if two bare
+  // nsIDOMSVGPathSeg constants are used as operands of the ?: operator below.
+  // In newer versions of GCC we would be able to turn off this warning using:
+  //
+  //#pragma GCC diagnostic push
+  //#pragma GCC diagnostic ignored "-Wenum-compare"
+  //...
+  //#pragma GCC diagnostic pop
+  //
+  // Unfortunately we need to support older versions of GCC. Instead, to
+  // eliminate this warning noise being sent to the console, we wrap the
+  // operands with PRUint32(...).
+
+  PRUint32 type = absCoords ?
+    PRUint32(nsIDOMSVGPathSeg::PATHSEG_MOVETO_ABS) :
+    PRUint32(nsIDOMSVGPathSeg::PATHSEG_MOVETO_REL);
+
+  return mPathSegList->AppendSeg(type, x, y);
+}
+
+nsresult
+nsSVGPathDataParserToInternal::StoreClosePath()
+{
+  return mPathSegList->AppendSeg(nsIDOMSVGPathSeg::PATHSEG_CLOSEPATH);
+}
+
+nsresult
+nsSVGPathDataParserToInternal::StoreLineTo(PRBool absCoords, float x, float y)
+{
+  PRUint32 type = absCoords ?
+    PRUint32(nsIDOMSVGPathSeg::PATHSEG_LINETO_ABS) :
+    PRUint32(nsIDOMSVGPathSeg::PATHSEG_LINETO_REL);
+
+  return mPathSegList->AppendSeg(type, x, y);
+}
+
+nsresult
+nsSVGPathDataParserToInternal::StoreHLineTo(PRBool absCoords, float x)
+{
+  PRUint32 type = absCoords ?
+    PRUint32(nsIDOMSVGPathSeg::PATHSEG_LINETO_HORIZONTAL_ABS) :
+    PRUint32(nsIDOMSVGPathSeg::PATHSEG_LINETO_HORIZONTAL_REL);
+
+  return mPathSegList->AppendSeg(type, x);
+}
+
+nsresult
+nsSVGPathDataParserToInternal::StoreVLineTo(PRBool absCoords, float y)
+{
+  PRUint32 type = absCoords ?
+    PRUint32(nsIDOMSVGPathSeg::PATHSEG_LINETO_VERTICAL_ABS) :
+    PRUint32(nsIDOMSVGPathSeg::PATHSEG_LINETO_VERTICAL_REL);
+
+  return mPathSegList->AppendSeg(type, y);
+}
+
+nsresult
+nsSVGPathDataParserToInternal::StoreCurveTo(PRBool absCoords,
+                                            float x, float y,
+                                            float x1, float y1,
+                                            float x2, float y2)
+{
+  PRUint32 type = absCoords ?
+    PRUint32(nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS) :
+    PRUint32(nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_REL);
+
+  return mPathSegList->AppendSeg(type, x1, y1, x2, y2, x, y);
+}
+
+nsresult
+nsSVGPathDataParserToInternal::StoreSmoothCurveTo(PRBool absCoords,
+                                                  float x, float y,
+                                                  float x2, float y2)
+{
+  PRUint32 type = absCoords ?
+    PRUint32(nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS) :
+    PRUint32(nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_REL);
+
+  return mPathSegList->AppendSeg(type, x2, y2, x, y);
+}
+
+nsresult
+nsSVGPathDataParserToInternal::StoreQuadCurveTo(PRBool absCoords,
+                                                float x, float y,
+                                                float x1, float y1)
+{
+  PRUint32 type = absCoords ?
+    PRUint32(nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_ABS) :
+    PRUint32(nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_REL);
+
+  return mPathSegList->AppendSeg(type, x1, y1, x, y);
+}
+
+nsresult
+nsSVGPathDataParserToInternal::StoreSmoothQuadCurveTo(PRBool absCoords,
+                                                      float x, float y)
+{
+  PRUint32 type = absCoords ?
+    PRUint32(nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS) :
+    PRUint32(nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL);
+
+  return mPathSegList->AppendSeg(type, x, y);
+}
+
+nsresult
+nsSVGPathDataParserToInternal::StoreEllipticalArc(PRBool absCoords,
+                                                  float x, float y,
+                                                  float r1, float r2,
+                                                  float angle,
+                                                  PRBool largeArcFlag,
+                                                  PRBool sweepFlag)
+{
+  PRUint32 type = absCoords ?
+    PRUint32(nsIDOMSVGPathSeg::PATHSEG_ARC_ABS) :
+    PRUint32(nsIDOMSVGPathSeg::PATHSEG_ARC_REL);
+
+  // We can only pass floats after 'type', and per the SVG spec for arc,
+  // non-zero args are treated at 'true'.
+  return mPathSegList->AppendSeg(type, r1, r2, angle,
+                                 largeArcFlag ? 1.0f : 0.0f,
+                                 sweepFlag ? 1.0f : 0.0f,
+                                 x, y);
+}
+
--- a/content/svg/content/src/nsSVGPathDataParser.h
+++ b/content/svg/content/src/nsSVGPathDataParser.h
@@ -39,19 +39,24 @@
 #ifndef __NS_SVGPATHDATAPARSER_H__
 #define __NS_SVGPATHDATAPARSER_H__
 
 #include "nsSVGDataParser.h"
 #include "nsCOMPtr.h"
 #include "nsCOMArray.h"
 #include "nsIDOMSVGPathSeg.h"
 #include "nsTArray.h"
+#include "gfxPoint.h"
 
 class nsSVGPathList;
 
+namespace mozilla {
+class SVGPathData;
+}
+
 ////////////////////////////////////////////////////////////////////////
 // nsSVGPathDataParser: a simple recursive descent parser that builds
 // nsIDOMSVGPathSegs from path data strings. The grammar for path data
 // can be found in SVG CR 20001102, chapter 8.
 
 class nsSVGPathDataParser : public nsSVGDataParser
 {
 protected:
@@ -135,20 +140,40 @@ protected:
   nsresult MatchEllipticalArcArgSeq(PRBool absCoords);
   nsresult MatchEllipticalArcArg(float* x, float* y,
                                  float* r1, float* r2, float* angle,
                                  PRBool* largeArcFlag, PRBool* sweepFlag);
   PRBool IsTokenEllipticalArcArgStarter();
   
  };
 
+class nsSVGArcConverter
+{
+public:
+  nsSVGArcConverter(const gfxPoint &from,
+                    const gfxPoint &to,
+                    const gfxPoint &radii,
+                    double angle,
+                    PRBool largeArcFlag,
+                    PRBool sweepFlag);
+  PRBool GetNextSegment(gfxPoint *cp1, gfxPoint *cp2, gfxPoint *to);
+protected:
+  PRInt32 mNumSegs, mSegIndex;
+  double mTheta, mDelta, mT;
+  double mSinPhi, mCosPhi;
+  double mRx, mRy;
+  gfxPoint mFrom, mC;
+};
+
 class nsSVGPathDataParserToInternal : public nsSVGPathDataParser
 {
 public:
-  nsSVGPathDataParserToInternal(nsSVGPathList *data) : mPathData(data) {}
+  nsSVGPathDataParserToInternal(mozilla::SVGPathData *aList)
+    : mPathSegList(aList)
+  {}
   nsresult Parse(const nsAString &aValue);
 
 protected:
   virtual nsresult StoreMoveTo(PRBool absCoords, float x, float y);
   virtual nsresult StoreClosePath();
   virtual nsresult StoreLineTo(PRBool absCoords, float x, float y);
   virtual nsresult StoreHLineTo(PRBool absCoords, float x);
   virtual nsresult StoreVLineTo(PRBool absCoords, float y);
@@ -160,83 +185,12 @@ protected:
                                     float x1, float y1);
   virtual nsresult StoreSmoothQuadCurveTo(PRBool absCoords,
                                           float x, float y);
   virtual nsresult StoreEllipticalArc(PRBool absCoords, float x, float y,
                                       float r1, float r2, float angle,
                                       PRBool largeArcFlag, PRBool sweepFlag);
 
 private:
-  nsSVGPathList *mPathData;
-  PRUint16 mPrevSeg;       // previous segment type for "smooth" segments"
-  float mPx, mPy;          // current point
-  float mCx, mCy;          // last control point for "smooth" segments
-  float mStartX, mStartY;  // start of current subpath, for closepath
-
-  // information used to construct PathList 
-  nsTArray<PRUint8> mCommands;
-  nsTArray<float>   mArguments;
-  PRUint32          mNumArguments;
-  PRUint32          mNumCommands;
-
-  // Pathdata helpers
-  nsresult ConvertArcToCurves(float x2, float y2, float rx, float ry,
-                              float angle, PRBool largeArcFlag, PRBool sweepFlag);
-
-  nsresult PathEnsureSpace(PRUint32 aNumArgs);
-  void PathAddCommandCode(PRUint8 aCommand);
-  nsresult PathMoveTo(float x, float y);
-  nsresult PathLineTo(float x, float y);
-  nsresult PathCurveTo(float x1, float y1, float x2, float y2, float x3, float y3);
-  nsresult PathClose();
-  void PathFini();
-};
-
-class nsSVGPathDataParserToDOM : public nsSVGPathDataParser
-{
-public:
-  nsSVGPathDataParserToDOM(nsCOMArray<nsIDOMSVGPathSeg>* data) : mData(data) {}
-
-protected:
-  virtual nsresult StoreMoveTo(PRBool absCoords, float x, float y);
-  virtual nsresult StoreClosePath();
-  virtual nsresult StoreLineTo(PRBool absCoords, float x, float y);
-  virtual nsresult StoreHLineTo(PRBool absCoords, float x);
-  virtual nsresult StoreVLineTo(PRBool absCoords, float y);
-  virtual nsresult StoreCurveTo(PRBool absCoords, float x, float y,
-                                float x1, float y1, float x2, float y2);
-  virtual nsresult StoreSmoothCurveTo(PRBool absCoords, float x, float y,
-                                      float x2, float y2);
-  virtual nsresult StoreQuadCurveTo(PRBool absCoords, float x, float y,
-                                    float x1, float y1);
-  virtual nsresult StoreSmoothQuadCurveTo(PRBool absCoords,
-                                          float x, float y);
-  virtual nsresult StoreEllipticalArc(PRBool absCoords, float x, float y,
-                                      float r1, float r2, float angle,
-                                      PRBool largeArcFlag, PRBool sweepFlag);
-
-private:
-  nsresult AppendSegment(nsIDOMSVGPathSeg* seg);
-
-  nsCOMArray<nsIDOMSVGPathSeg>* mData;
-};
-
-class nsSVGArcConverter
-{
-public:
-  nsSVGArcConverter(float x1, float y1,
-                    float x2, float y2,
-                    float rx, float ry,
-                    float angle,
-                    PRBool largeArcFlag,
-                    PRBool sweepFlag);
-  PRBool GetNextSegment(float *x1, float *y1,
-                        float *x2, float *y2,
-                        float *x3, float *y3);
-protected:
-  PRInt32 mNumSegs, mSegIndex;
-  float mTheta, mDelta, mT;
-  float mSinPhi, mCosPhi;
-  float mX1, mY1, mRx, mRy, mCx, mCy;
-
+  mozilla::SVGPathData *mPathSegList;
 };
 
 #endif // __NS_SVGPATHDATAPARSER_H__
--- a/content/svg/content/src/nsSVGPathElement.cpp
+++ b/content/svg/content/src/nsSVGPathElement.cpp
@@ -32,29 +32,31 @@
  * 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 "nsGkAtoms.h"
-#include "nsSVGPathSegList.h"
 #include "nsIDOMSVGPathSeg.h"
-#include "nsSVGPathSeg.h"
+#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 "gfxContext.h"
 #include "gfxPlatform.h"
 
+using namespace mozilla;
+
 nsSVGElement::NumberInfo nsSVGPathElement::sNumberInfo = 
                                                   { &nsGkAtoms::pathLength, 0 };
 
 NS_IMPL_NS_NEW_SVG_ELEMENT(Path)
 
 //----------------------------------------------------------------------
 // nsISupports methods
 
@@ -73,22 +75,16 @@ NS_INTERFACE_MAP_END_INHERITING(nsSVGPat
 //----------------------------------------------------------------------
 // Implementation
 
 nsSVGPathElement::nsSVGPathElement(already_AddRefed<nsINodeInfo> aNodeInfo)
   : nsSVGPathElementBase(aNodeInfo)
 {
 }
 
-nsSVGPathElement::~nsSVGPathElement()
-{
-  if (mSegments)
-    NS_REMOVE_SVGVALUE_OBSERVER(mSegments);
-}
-
 //----------------------------------------------------------------------
 // nsIDOMNode methods
 
 NS_IMPL_ELEMENT_CLONE_WITH_INIT(nsSVGPathElement)
 
 //----------------------------------------------------------------------
 // nsIDOMSVGPathElement methods:
 
@@ -136,48 +132,17 @@ nsSVGPathElement::GetPointAtLength(float
   return NS_NewSVGPoint(_retval, flat->FindPoint(gfxPoint(distance, 0)));
 }
 
 /* unsigned long getPathSegAtLength (in float distance); */
 NS_IMETHODIMP
 nsSVGPathElement::GetPathSegAtLength(float distance, PRUint32 *_retval)
 {
   NS_ENSURE_FINITE(distance, NS_ERROR_ILLEGAL_VALUE);
-
-  //Check if mSegments is null
-  nsresult rv = CreatePathSegList();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  PRUint32 i = 0, numSegments;
-  float distCovered = 0;
-  nsSVGPathSegTraversalState ts;
-
-  mSegments->GetNumberOfItems(&numSegments);
-
-  //  There is no need to check to see if distance falls within the last segment
-  //  because if distance is longer than the total length of the path we return 
-  //  the index of the final segment anyway.
-  while (distCovered < distance && i + 1 < numSegments) {
-    nsCOMPtr<nsIDOMSVGPathSeg> segment;
-    mSegments->GetItem(i, getter_AddRefs(segment));
-    nsSVGPathSeg* curSeg = static_cast<nsSVGPathSeg*>(segment.get());
-    if (i == 0) {
-      curSeg->GetLength(&ts);
-    } else {
-      distCovered += curSeg->GetLength(&ts);
-    }
-
-    if (distCovered >= distance) {
-      break;
-    }
-    ++i;
-  }
-
-  *_retval = i;
-
+  *_retval = mD.GetAnimValue().GetPathSegAtLength(distance);
   return NS_OK;
 }
 
 /* nsIDOMSVGPathSegClosePath createSVGPathSegClosePath (); */
 NS_IMETHODIMP
 nsSVGPathElement::CreateSVGPathSegClosePath(nsIDOMSVGPathSegClosePath **_retval)
 {
   nsIDOMSVGPathSeg* seg = NS_NewSVGPathSegClosePath();
@@ -362,74 +327,49 @@ NS_IMETHODIMP
 nsSVGPathElement::CreateSVGPathSegCurvetoQuadraticSmoothRel(float x, float y, nsIDOMSVGPathSegCurvetoQuadraticSmoothRel **_retval)
 {
   NS_ENSURE_FINITE2(x, y, NS_ERROR_ILLEGAL_VALUE);
   nsIDOMSVGPathSeg* seg = NS_NewSVGPathSegCurvetoQuadraticSmoothRel(x, y);
   NS_ENSURE_TRUE(seg, NS_ERROR_OUT_OF_MEMORY);
   return CallQueryInterface(seg, _retval);
 }
 
-nsresult
-nsSVGPathElement::CreatePathSegList()
-{
-  if (mSegments)
-    return NS_OK;
-
-  nsresult rv = NS_NewSVGPathSegList(getter_AddRefs(mSegments));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<nsISVGValue> value = do_QueryInterface(mSegments);
-
-  nsAutoString d;
-  if (NS_SUCCEEDED(GetAttr(kNameSpaceID_None, nsGkAtoms::d, d)))
-    value->SetValueString(d);
-
-  NS_ADD_SVGVALUE_OBSERVER(mSegments);
-
-  return NS_OK;
-}
-
 //----------------------------------------------------------------------
 // nsSVGElement methods
 
 nsSVGElement::NumberAttributesInfo
 nsSVGPathElement::GetNumberInfo()
 {
   return NumberAttributesInfo(&mPathLength, &sNumberInfo, 1);
 }
 
 //----------------------------------------------------------------------
 // nsIDOMSVGAnimatedPathData methods:
 
 /* readonly attribute nsIDOMSVGPathSegList pathSegList; */
 NS_IMETHODIMP nsSVGPathElement::GetPathSegList(nsIDOMSVGPathSegList * *aPathSegList)
 {
-  nsresult rv = CreatePathSegList();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  *aPathSegList = mSegments;
-  NS_ADDREF(*aPathSegList);
-  return NS_OK;
+  void *key = mD.GetBaseValKey();
+  *aPathSegList = DOMSVGPathSegList::GetDOMWrapper(key, this, PR_FALSE).get();
+  return *aPathSegList ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
 }
 
 /* readonly attribute nsIDOMSVGPathSegList normalizedPathSegList; */
 NS_IMETHODIMP nsSVGPathElement::GetNormalizedPathSegList(nsIDOMSVGPathSegList * *aNormalizedPathSegList)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 /* readonly attribute nsIDOMSVGPathSegList animatedPathSegList; */
 NS_IMETHODIMP nsSVGPathElement::GetAnimatedPathSegList(nsIDOMSVGPathSegList * *aAnimatedPathSegList)
 {
-  nsresult rv = CreatePathSegList();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  *aAnimatedPathSegList = mSegments;
-  NS_ADDREF(*aAnimatedPathSegList);
-  return NS_OK;
+  void *key = mD.GetAnimValKey();
+  *aAnimatedPathSegList =
+    DOMSVGPathSegList::GetDOMWrapper(key, this, PR_TRUE).get();
+  return *aAnimatedPathSegList ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
 }
 
 /* readonly attribute nsIDOMSVGPathSegList animatedNormalizedPathSegList; */
 NS_IMETHODIMP nsSVGPathElement::GetAnimatedNormalizedPathSegList(nsIDOMSVGPathSegList * *aAnimatedNormalizedPathSegList)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
@@ -442,85 +382,20 @@ nsSVGPathElement::IsAttributeMapped(cons
   static const MappedAttributeEntry* const map[] = {
     sMarkersMap
   };
 
   return FindAttributeDependence(name, map, NS_ARRAY_LENGTH(map)) ||
     nsSVGPathElementBase::IsAttributeMapped(name);
 }
 
-nsresult
-nsSVGPathElement::BeforeSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
-                               const nsAString* aValue, PRBool aNotify)
-{
-  if (aNamespaceID == kNameSpaceID_None && aName == nsGkAtoms::d) {
-    if (mSegments) {
-      NS_REMOVE_SVGVALUE_OBSERVER(mSegments);
-      mSegments = nsnull;
-    }
-
-    if (aValue) {
-      nsSVGPathDataParserToInternal parser(&mPathData);
-      nsresult rv = parser.Parse(*aValue);
-      if (NS_FAILED(rv)) {
-        ReportAttributeParseFailure(GetOwnerDoc(), aName, *aValue);
-      }
-    } else {
-      mPathData.Clear();
-    }
-  }
-
-  return nsSVGPathElementBase::BeforeSetAttr(aNamespaceID, aName,
-                                             aValue, aNotify);
-}
-
-NS_IMETHODIMP
-nsSVGPathElement::WillModifySVGObservable(nsISVGValue* observable,
-                                          nsISVGValue::modificationType aModType)
-{
-  nsCOMPtr<nsIDOMSVGPathSegList> list = do_QueryInterface(observable);
-
-  if (list && mSegments == list) {
-    return NS_OK;
-  }
-
-  return nsSVGPathElementBase::WillModifySVGObservable(observable, aModType);
-}
-
-NS_IMETHODIMP
-nsSVGPathElement::DidModifySVGObservable(nsISVGValue* observable,
-                                         nsISVGValue::modificationType aModType)
-{
-  nsCOMPtr<nsIDOMSVGPathSegList> list = do_QueryInterface(observable);
-
-  if (list && mSegments == list) {
-    nsCOMPtr<nsISVGValue> value = do_QueryInterface(mSegments);
-    nsAutoString d;
-    nsresult rv = value->GetValueString(d);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    // Want to keep the seglist alive - SetAttr normally invalidates it
-    nsCOMPtr<nsIDOMSVGPathSegList> deathGrip = mSegments;
-    mSegments = nsnull;
-
-    rv = SetAttr(kNameSpaceID_None, nsGkAtoms::d, d, PR_TRUE);
-
-    // Restore seglist
-    mSegments = deathGrip;
-
-    return rv;
-  }
-
-  return nsSVGPathElementBase::DidModifySVGObservable(observable, aModType);
-}
-
 already_AddRefed<gfxFlattenedPath>
 nsSVGPathElement::GetFlattenedPath(const gfxMatrix &aMatrix)
 {
-  return mPathData.GetFlattenedPath(aMatrix);
+  return mD.GetAnimValue().ToFlattenedPath(aMatrix);
 }
 
 //----------------------------------------------------------------------
 // nsSVGPathGeometryElement methods
 
 PRBool
 nsSVGPathElement::AttributeDefinesGeometry(const nsIAtom *aName)
 {
@@ -532,522 +407,20 @@ nsSVGPathElement::AttributeDefinesGeomet
 }
 
 PRBool
 nsSVGPathElement::IsMarkable()
 {
   return PR_TRUE;
 }
 
-static double
-CalcVectorAngle(double ux, double uy, double vx, double vy)
-{
-  double ta = atan2(uy, ux);
-  double tb = atan2(vy, vx);
-  if (tb >= ta)
-    return tb-ta;
-  return 2 * M_PI - (ta-tb);
-}
-
 void
 nsSVGPathElement::GetMarkPoints(nsTArray<nsSVGMark> *aMarks)
 {
-  if (NS_FAILED(CreatePathSegList()))
-    return;
-
-  PRUint32 count;
-  mSegments->GetNumberOfItems(&count);
-  nsCOMPtr<nsIDOMSVGPathSeg> segment;
-
-  float cx = 0.0f; // current point
-  float cy = 0.0f;
-
-  float cx1 = 0.0f; // last controlpoint (for s,S,t,T)
-  float cy1 = 0.0f;
-
-  PRUint16 lastSegmentType = nsIDOMSVGPathSeg::PATHSEG_UNKNOWN;
-
-  float px = 0, py = 0;    // subpath initial point
-  float pathAngle = 0;
-  PRUint32 pathIndex = 0;
-
-  float prevAngle = 0, startAngle = 0, endAngle = 0;
-
-  PRBool newSegment = PR_FALSE;
-
-  PRUint32 i;
-  for (i = 0; i < count; ++i) {
-    nsCOMPtr<nsIDOMSVGPathSeg> segment;
-    mSegments->GetItem(i, getter_AddRefs(segment));
-
-    PRUint16 type = nsIDOMSVGPathSeg::PATHSEG_UNKNOWN;
-    segment->GetPathSegType(&type);
-
-    float x, y;
-    PRBool absCoords = PR_FALSE;
-
-    switch (type) {
-    case nsIDOMSVGPathSeg::PATHSEG_CLOSEPATH:
-    {
-      x = px;
-      y = py;
-      startAngle = endAngle = atan2(y - cy, x - cx);
-    }
-    break;
-
-    case nsIDOMSVGPathSeg::PATHSEG_MOVETO_ABS:
-      absCoords = PR_TRUE;
-    case nsIDOMSVGPathSeg::PATHSEG_MOVETO_REL:
-    {
-      if (!absCoords) {
-        nsCOMPtr<nsIDOMSVGPathSegMovetoRel> moveseg = do_QueryInterface(segment);
-        NS_ASSERTION(moveseg, "interface not implemented");
-        moveseg->GetX(&x);
-        moveseg->GetY(&y);
-        x += cx;
-        y += cy;
-      } else {
-        nsCOMPtr<nsIDOMSVGPathSegMovetoAbs> moveseg = do_QueryInterface(segment);
-        NS_ASSERTION(moveseg, "interface not implemented");
-        moveseg->GetX(&x);
-        moveseg->GetY(&y);
-      }
-      px = x;
-      py = y;
-      startAngle = endAngle = prevAngle;
-      newSegment = PR_TRUE;
-    }
-    break;
-
-    case nsIDOMSVGPathSeg::PATHSEG_LINETO_ABS:
-      absCoords = PR_TRUE;
-    case nsIDOMSVGPathSeg::PATHSEG_LINETO_REL:
-    {
-      if (!absCoords) {
-        nsCOMPtr<nsIDOMSVGPathSegLinetoRel> lineseg = do_QueryInterface(segment);
-        NS_ASSERTION(lineseg, "interface not implemented");
-        lineseg->GetX(&x);
-        lineseg->GetY(&y);
-        x += cx;
-        y += cy;
-      } else {
-        nsCOMPtr<nsIDOMSVGPathSegLinetoAbs> lineseg = do_QueryInterface(segment);
-        NS_ASSERTION(lineseg, "interface not implemented");
-        lineseg->GetX(&x);
-        lineseg->GetY(&y);
-      }
-      startAngle = endAngle = atan2(y - cy, x - cx);
-    }
-    break;
-
-    case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS:
-      absCoords = PR_TRUE;
-    case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_REL:
-    {
-      float x1, y1, x2, y2;
-      if (!absCoords) {
-        nsCOMPtr<nsIDOMSVGPathSegCurvetoCubicRel> curveseg = do_QueryInterface(segment);
-        NS_ASSERTION(curveseg, "interface not implemented");
-        curveseg->GetX(&x);
-        curveseg->GetY(&y);
-        curveseg->GetX1(&x1);
-        curveseg->GetY1(&y1);
-        curveseg->GetX2(&x2);
-        curveseg->GetY2(&y2);
-        x  += cx;
-        y  += cy;
-        x1 += cx;
-        y1 += cy;
-        x2 += cx;
-        y2 += cy;
-      } else {
-        nsCOMPtr<nsIDOMSVGPathSegCurvetoCubicAbs> curveseg = do_QueryInterface(segment);
-        NS_ASSERTION(curveseg, "interface not implemented");
-        curveseg->GetX(&x);
-        curveseg->GetY(&y);
-        curveseg->GetX1(&x1);
-        curveseg->GetY1(&y1);
-        curveseg->GetX2(&x2);
-        curveseg->GetY2(&y2);
-      }
-
-      cx1 = x2;
-      cy1 = y2;
-
-      if (x1 == cx && y1 == cy) {
-        x1 = x2;
-        y1 = y2;
-      }
-
-      if (x2 == x && y2 == y) {
-        x2 = x1;
-        y2 = y1;
-      }
-
-      startAngle = atan2(y1 - cy, x1 - cx);
-      endAngle = atan2(y - y2, x - x2);
-    }
-    break;
-
-    case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_ABS:
-      absCoords = PR_TRUE;
-    case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_REL:
-    {
-      float x1, y1;
-
-      if (!absCoords) {
-        nsCOMPtr<nsIDOMSVGPathSegCurvetoQuadraticRel> curveseg = do_QueryInterface(segment);
-        NS_ASSERTION(curveseg, "interface not implemented");
-        curveseg->GetX(&x);
-        curveseg->GetY(&y);
-        curveseg->GetX1(&x1);
-        curveseg->GetY1(&y1);
-        x  += cx;
-        y  += cy;
-        x1 += cx;
-        y1 += cy;
-      } else {
-        nsCOMPtr<nsIDOMSVGPathSegCurvetoQuadraticAbs> curveseg = do_QueryInterface(segment);
-        NS_ASSERTION(curveseg, "interface not implemented");
-        curveseg->GetX(&x);
-        curveseg->GetY(&y);
-        curveseg->GetX1(&x1);
-        curveseg->GetY1(&y1);
-      }
-
-      cx1 = x1;
-      cy1 = y1;
-
-      startAngle = atan2(y1 - cy, x1 - cx);
-      endAngle = atan2(y - y1, x - x1);
-    }
-    break;
-
-    case nsIDOMSVGPathSeg::PATHSEG_ARC_ABS:
-      absCoords = PR_TRUE;
-    case nsIDOMSVGPathSeg::PATHSEG_ARC_REL:
-    {
-      float r1, r2, angle;
-      PRBool largeArcFlag, sweepFlag;
-
-      if (!absCoords) {
-        nsCOMPtr<nsIDOMSVGPathSegArcRel> arcseg = do_QueryInterface(segment);
-        NS_ASSERTION(arcseg, "interface not implemented");
-        arcseg->GetX(&x);
-        arcseg->GetY(&y);
-        arcseg->GetR1(&r1);
-        arcseg->GetR2(&r2);
-        arcseg->GetAngle(&angle);
-        arcseg->GetLargeArcFlag(&largeArcFlag);
-        arcseg->GetSweepFlag(&sweepFlag);
-
-        x  += cx;
-        y  += cy;
-      } else {
-        nsCOMPtr<nsIDOMSVGPathSegArcAbs> arcseg = do_QueryInterface(segment);
-        NS_ASSERTION(arcseg, "interface not implemented");
-        arcseg->GetX(&x);
-        arcseg->GetY(&y);
-        arcseg->GetR1(&r1);
-        arcseg->GetR2(&r2);
-        arcseg->GetAngle(&angle);
-        arcseg->GetLargeArcFlag(&largeArcFlag);
-        arcseg->GetSweepFlag(&sweepFlag);
-      }
-
-      /* check for degenerate ellipse */
-      if (r1 == 0.0 || r2 == 0.0) {
-        startAngle = endAngle = atan2(y - cy, x - cx);
-        break;
-      }
-
-      r1 = fabs(r1);  r2 = fabs(r2);
-
-      float xp, yp, cxp, cyp;
-
-      /* slope fun&games ... see SVG spec, section F.6 */
-      angle = angle*M_PI/180.0;
-      xp = cos(angle)*(cx-x)/2.0 + sin(angle)*(cy-y)/2.0;
-      yp = -sin(angle)*(cx-x)/2.0 + cos(angle)*(cy-y)/2.0;
-
-      /* make sure radii are large enough */
-      float root, numerator = r1*r1*r2*r2 - r1*r1*yp*yp - r2*r2*xp*xp;
-      if (numerator < 0.0) {
-        float s = sqrt(1.0 - numerator/(r1*r1*r2*r2));
-        r1 *= s;
-        r2 *= s;
-        root = 0.0;
-      } else {
-        root = sqrt(numerator/(r1*r1*yp*yp + r2*r2*xp*xp));
-        if (largeArcFlag == sweepFlag)
-          root = -root;
-      }
-      cxp = root*r1*yp/r2;
-      cyp = -root*r2*xp/r1;
-
-      float theta, delta;
-      theta = CalcVectorAngle(1.0, 0.0,  (xp-cxp)/r1, (yp-cyp)/r2);
-      delta  = CalcVectorAngle((xp-cxp)/r1, (yp-cyp)/r2,
-                               (-xp-cxp)/r1, (-yp-cyp)/r2);
-      if (!sweepFlag && delta > 0)
-        delta -= 2.0*M_PI;
-      else if (sweepFlag && delta < 0)
-        delta += 2.0*M_PI;
-
-      float tx1, ty1, tx2, ty2;
-      tx1 = -cos(angle)*r1*sin(theta) - sin(angle)*r2*cos(theta);
-      ty1 = -sin(angle)*r1*sin(theta) + cos(angle)*r2*cos(theta);
-      tx2 = -cos(angle)*r1*sin(theta+delta) - sin(angle)*r2*cos(theta+delta);
-      ty2 = -sin(angle)*r1*sin(theta+delta) + cos(angle)*r2*cos(theta+delta);
-
-      if (delta < 0.0f) {
-        tx1 = -tx1;
-        ty1 = -ty1;
-        tx2 = -tx2;
-        ty2 = -ty2;
-      }
-
-      startAngle = atan2(ty1, tx1);
-      endAngle = atan2(ty2, tx2);
-    }
-    break;
-
-    case nsIDOMSVGPathSeg::PATHSEG_LINETO_HORIZONTAL_ABS:
-      absCoords = PR_TRUE;
-    case nsIDOMSVGPathSeg::PATHSEG_LINETO_HORIZONTAL_REL:
-    {
-      y = cy;
-      if (!absCoords) {
-        nsCOMPtr<nsIDOMSVGPathSegLinetoHorizontalRel> lineseg = do_QueryInterface(segment);
-        NS_ASSERTION(lineseg, "interface not implemented");
-        lineseg->GetX(&x);
-        x += cx;
-      } else {
-        nsCOMPtr<nsIDOMSVGPathSegLinetoHorizontalAbs> lineseg = do_QueryInterface(segment);
-        NS_ASSERTION(lineseg, "interface not implemented");
-        lineseg->GetX(&x);
-      }
-      startAngle = endAngle = atan2(0, x - cx);
-    }
-    break;
-
-    case nsIDOMSVGPathSeg::PATHSEG_LINETO_VERTICAL_ABS:
-      absCoords = PR_TRUE;
-    case nsIDOMSVGPathSeg::PATHSEG_LINETO_VERTICAL_REL:
-    {
-      x = cx;
-      if (!absCoords) {
-        nsCOMPtr<nsIDOMSVGPathSegLinetoVerticalRel> lineseg = do_QueryInterface(segment);
-        NS_ASSERTION(lineseg, "interface not implemented");
-        lineseg->GetY(&y);
-        y += cy;
-      } else {
-        nsCOMPtr<nsIDOMSVGPathSegLinetoVerticalAbs> lineseg = do_QueryInterface(segment);
-        NS_ASSERTION(lineseg, "interface not implemented");
-        lineseg->GetY(&y);
-      }
-      startAngle = endAngle = atan2(y - cy, 0);
-    }
-    break;
-
-    case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS:
-      absCoords = PR_TRUE;
-    case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_REL:
-    {
-      float x1, y1, x2, y2;
-
-      if (lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_REL        ||
-          lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS        ||
-          lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_REL ||
-          lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS ) {
-        // the first controlpoint is the reflection of the last one about the current point:
-        x1 = 2*cx - cx1;
-        y1 = 2*cy - cy1;
-      }
-      else {
-        // the first controlpoint is equal to the current point:
-        x1 = cx;
-        y1 = cy;
-      }
-
-      if (!absCoords) {
-        nsCOMPtr<nsIDOMSVGPathSegCurvetoCubicSmoothRel> curveseg = do_QueryInterface(segment);
-        NS_ASSERTION(curveseg, "interface not implemented");
-        curveseg->GetX(&x);
-        curveseg->GetY(&y);
-        curveseg->GetX2(&x2);
-        curveseg->GetY2(&y2);
-        x  += cx;
-        y  += cy;
-        x2 += cx;
-        y2 += cy;
-      } else {
-        nsCOMPtr<nsIDOMSVGPathSegCurvetoCubicSmoothAbs> curveseg = do_QueryInterface(segment);
-        NS_ASSERTION(curveseg, "interface not implemented");
-        curveseg->GetX(&x);
-        curveseg->GetY(&y);
-        curveseg->GetX2(&x2);
-        curveseg->GetY2(&y2);
-      }
-
-      cx1 = x2;
-      cy1 = y2;
-
-      if (x1 == cx && y1 == cy) {
-        x1 = x2;
-        y1 = y2;
-      }
-
-      if (x2 == x && y2 == y) {
-        x2 = x1;
-        y2 = y1;
-      }
-
-      startAngle = atan2(y1 - cy, x1 - cx);
-      endAngle = atan2(y - y2, x - x2);
-    }
-    break;
-
-    case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS:
-      absCoords = PR_TRUE;
-    case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL:
-      {
-        float x1, y1;
-
-        if (lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_REL        ||
-            lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_ABS        ||
-            lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL ||
-            lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS ) {
-          // the first controlpoint is the reflection of the last one about the current point:
-          x1 = 2*cx - cx1;
-          y1 = 2*cy - cy1;
-        }
-        else {
-          // the first controlpoint is equal to the current point:
-          x1 = cx;
-          y1 = cy;
-        }
-
-        if (!absCoords) {
-          nsCOMPtr<nsIDOMSVGPathSegCurvetoQuadraticSmoothRel> curveseg = do_QueryInterface(segment);
-          NS_ASSERTION(curveseg, "interface not implemented");
-          curveseg->GetX(&x);
-          curveseg->GetY(&y);
-          x  += cx;
-          y  += cy;
-        } else {
-          nsCOMPtr<nsIDOMSVGPathSegCurvetoQuadraticSmoothAbs> curveseg = do_QueryInterface(segment);
-          NS_ASSERTION(curveseg, "interface not implemented");
-          curveseg->GetX(&x);
-          curveseg->GetY(&y);
-        }
-
-        cx1 = x1;
-        cy1 = y1;
-
-        startAngle = atan2(y1 - cy, x1 - cx);
-        endAngle = atan2(y - y1, x - x1);
-      }
-      break;
-
-    default:
-      NS_ASSERTION(1==0, "unknown path segment");
-      break;
-    }
-    lastSegmentType = type;
-
-    if (newSegment &&
-        type != nsIDOMSVGPathSeg::PATHSEG_MOVETO_ABS &&
-        type != nsIDOMSVGPathSeg::PATHSEG_MOVETO_REL) {
-      pathIndex = aMarks->Length() - 1;
-      pathAngle = startAngle;
-      aMarks->ElementAt(pathIndex).angle = pathAngle;
-      newSegment = PR_FALSE;
-      prevAngle = endAngle;
-    } else if (type == nsIDOMSVGPathSeg::PATHSEG_MOVETO_ABS ||
-               type == nsIDOMSVGPathSeg::PATHSEG_MOVETO_REL) {
-      if (aMarks->Length())
-        aMarks->ElementAt(aMarks->Length() - 1).angle = prevAngle;
-    } else {
-      aMarks->ElementAt(aMarks->Length() - 1).angle =
-        nsSVGUtils::AngleBisect(prevAngle, startAngle);
-      prevAngle = endAngle;
-    }
-
-    aMarks->AppendElement(nsSVGMark(x, y, 0));
-
-    if (type == nsIDOMSVGPathSeg::PATHSEG_CLOSEPATH) {
-      prevAngle = nsSVGUtils::AngleBisect(endAngle, pathAngle);
-      aMarks->ElementAt(pathIndex).angle = prevAngle;
-    }
-
-    cx = x;
-    cy = y;
-  }
-
-  if (aMarks->Length())
-    aMarks->ElementAt(aMarks->Length() - 1).angle = prevAngle;
+  mD.GetAnimValue().GetMarkerPositioningData(aMarks);
 }
 
 void
 nsSVGPathElement::ConstructPath(gfxContext *aCtx)
 {
-  mPathData.Playback(aCtx);
-}
-
-//==================================================================
-// nsSVGPathList
-
-void
-nsSVGPathList::Clear()
-{
-  if (mArguments) {
-    free(mArguments);
-    mArguments = nsnull;
-  }
-  mNumCommands = 0;
-  mNumArguments = 0;
+  mD.GetAnimValue().ConstructPath(aCtx);
 }
 
-void
-nsSVGPathList::Playback(gfxContext *aCtx)
-{
-  float *args = mArguments;
-  for (PRUint32 i = 0; i < mNumCommands; i++) {
-    PRUint8 command =
-      reinterpret_cast<PRUint8*>(mArguments + mNumArguments)[i / 4];
-    command = (command >> (2 * (i % 4))) & 0x3;
-    switch (command) {
-    case MOVETO:
-      aCtx->MoveTo(gfxPoint(args[0], args[1]));
-      args += 2;
-      break;
-    case LINETO:
-      aCtx->LineTo(gfxPoint(args[0], args[1]));
-      args += 2;
-      break;
-    case CURVETO:
-      aCtx->CurveTo(gfxPoint(args[0], args[1]),
-                    gfxPoint(args[2], args[3]),
-                    gfxPoint(args[4], args[5]));
-      args += 6;
-      break;
-    case CLOSEPATH:
-      aCtx->ClosePath();
-      break;
-    default:
-      break;
-    }
-  }
-}
-
-already_AddRefed<gfxFlattenedPath>
-nsSVGPathList::GetFlattenedPath(const gfxMatrix& aMatrix)
-{
-  nsRefPtr<gfxContext> ctx =
-    new gfxContext(gfxPlatform::GetPlatform()->ScreenReferenceSurface());
-
-  ctx->SetMatrix(aMatrix);
-  Playback(ctx);
-  ctx->IdentityMatrix();
-
-  return ctx->GetFlattenedPath();
-}
--- a/content/svg/content/src/nsSVGPathElement.h
+++ b/content/svg/content/src/nsSVGPathElement.h
@@ -38,95 +38,75 @@
 
 #ifndef __NS_SVGPATHELEMENT_H__
 #define __NS_SVGPATHELEMENT_H__
 
 #include "nsSVGPathGeometryElement.h"
 #include "nsIDOMSVGPathElement.h"
 #include "nsIDOMSVGAnimatedPathData.h"
 #include "nsSVGNumber2.h"
+#include "SVGAnimatedPathSegList.h"
 #include "gfxPath.h"
 
 class gfxContext;
 
-class nsSVGPathList
-{
-friend class nsSVGPathDataParserToInternal;
-
-public:
-  enum { MOVETO, LINETO, CURVETO, CLOSEPATH };
-  nsSVGPathList() : mArguments(nsnull), mNumCommands(0), mNumArguments(0) {}
-  ~nsSVGPathList() { Clear(); }
-  void Playback(gfxContext *aCtx);
-  already_AddRefed<gfxFlattenedPath> GetFlattenedPath(const gfxMatrix &aMatrix);
-  void Clear();
-
-protected:
-  float   *mArguments;
-  PRUint32 mNumCommands;
-  PRUint32 mNumArguments;
-};
-
 typedef nsSVGPathGeometryElement nsSVGPathElementBase;
 
 class nsSVGPathElement : public nsSVGPathElementBase,
                          public nsIDOMSVGPathElement,
                          public nsIDOMSVGAnimatedPathData
 {
 friend class nsSVGPathFrame;
 friend class nsSVGTextPathFrame;
 
 protected:
   friend nsresult NS_NewSVGPathElement(nsIContent **aResult,
                                        already_AddRefed<nsINodeInfo> aNodeInfo);
   nsSVGPathElement(already_AddRefed<nsINodeInfo> aNodeInfo);
-  virtual ~nsSVGPathElement();
 
 public:
+  typedef mozilla::SVGAnimatedPathSegList SVGAnimatedPathSegList;
   // interfaces:
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIDOMSVGPATHELEMENT
   NS_DECL_NSIDOMSVGANIMATEDPATHDATA
 
   // xxx I wish we could use virtual inheritance
   NS_FORWARD_NSIDOMNODE(nsSVGPathElementBase::)
   NS_FORWARD_NSIDOMELEMENT(nsSVGPathElementBase::)
   NS_FORWARD_NSIDOMSVGELEMENT(nsSVGPathElementBase::)
 
   // nsIContent interface
   NS_IMETHOD_(PRBool) IsAttributeMapped(const nsIAtom* name) const;
 
-  // nsISVGValueObserver
-  NS_IMETHOD WillModifySVGObservable(nsISVGValue* observable,
-                                     nsISVGValue::modificationType aModType);
-  NS_IMETHOD DidModifySVGObservable(nsISVGValue* observable,
-                                    nsISVGValue::modificationType aModType);
-
   // nsSVGPathGeometryElement methods:
   virtual PRBool AttributeDefinesGeometry(const nsIAtom *aName);
   virtual PRBool IsMarkable();
   virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks);
   virtual void ConstructPath(gfxContext *aCtx);
 
   virtual already_AddRefed<gfxFlattenedPath> GetFlattenedPath(const gfxMatrix &aMatrix);
 
   // nsIContent interface
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
-  virtual nsresult BeforeSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
-                                 const nsAString* aValue, PRBool aNotify);
 
   virtual nsXPCClassInfo* GetClassInfo();
+
+  virtual SVGAnimatedPathSegList* GetAnimPathSegList() {
+    return &mD;
+  }
+
+  virtual nsIAtom* GetPathDataAttrName() const {
+    return nsGkAtoms::d;
+  }
+
 protected:
 
   // nsSVGElement method
   virtual NumberAttributesInfo GetNumberInfo();
 
-  // Helper for lazily creating pathseg list
-  nsresult CreatePathSegList();
-
-  nsCOMPtr<nsIDOMSVGPathSegList> mSegments;
+  SVGAnimatedPathSegList mD;
   nsSVGNumber2 mPathLength;
   static NumberInfo sNumberInfo;
-  nsSVGPathList mPathData;
 };
 
 #endif
deleted file mode 100644
--- a/content/svg/content/src/nsSVGPathSeg.cpp
+++ /dev/null
@@ -1,2405 +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 "nsSVGPathSeg.h"
-#include "prdtoa.h"
-#include "nsSVGValue.h"
-#include "nsTextFormatter.h"
-#include "nsContentUtils.h"
-
-
-struct PathPoint {
-  float x, y;
-};
-
-//----------------------------------------------------------------------
-// Error threshold to use when calculating the length of Bezier curves
-static const float PATH_SEG_LENGTH_TOLERANCE = 0.0000001f;
-
-//----------------------------------------------------------------------
-// Maximum recursion limit for length calculation
-static const PRUint32 MAX_STEPS = 10;
-
-//----------------------------------------------------------------------
-// implementation helper macros
-
-#define NS_IMPL_SVGPATHSEG(type, letter)                      \
-NS_IMETHODIMP                                                 \
-GetPathSegType(PRUint16 *aPathSegType) {                      \
-  *aPathSegType = type; return NS_OK; }                       \
-                                                              \
-NS_IMETHODIMP                                                 \
-GetPathSegTypeAsLetter(nsAString & aPathSegTypeAsLetter) {    \
-  aPathSegTypeAsLetter.Assign(letter);                        \
-  return NS_OK; }
-
-#define NS_IMPL_NSISUPPORTS_SVGPATHSEG(basename)              \
-NS_IMPL_ADDREF(ns##basename)                                  \
-NS_IMPL_RELEASE(ns##basename)                                 \
-                                                              \
-DOMCI_DATA(basename, ns##basename)                            \
-                                                              \
-NS_INTERFACE_MAP_BEGIN(ns##basename)                          \
-  NS_INTERFACE_MAP_ENTRY(nsIDOM##basename)                    \
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(basename)          \
-NS_INTERFACE_MAP_END_INHERITING(nsSVGPathSeg)
-
-//----------------------------------------------------------------------
-// GetLength Helper Functions
-
-static float GetDistance(float x1, float x2, float y1, float y2)
-{
-  return sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
-}
-
-static void SplitQuadraticBezier(PathPoint *curve,
-                                 PathPoint *left,
-                                 PathPoint *right)
-{
-  left[0].x = curve[0].x;
-  left[0].y = curve[0].y;
-  right[2].x = curve[2].x;
-  right[2].y = curve[2].y;
-  left[1].x = (curve[0].x + curve[1].x) / 2;
-  left[1].y = (curve[0].y + curve[1].y) / 2;
-  right[1].x = (curve[1].x + curve[2].x) / 2;
-  right[1].y = (curve[1].y + curve[2].y) / 2;
-  left[2].x = right[0].x = (left[1].x + right[1].x) / 2;
-  left[2].y = right[0].y = (left[1].y + right[1].y) / 2;
-}
-
-static void SplitCubicBezier(PathPoint *curve,
-                             PathPoint *left,
-                             PathPoint *right)
-{
-  PathPoint tmp;
-  tmp.x = (curve[1].x + curve[2].x) / 4;
-  tmp.y = (curve[1].y + curve[2].y) / 4;
-  left[0].x = curve[0].x;
-  left[0].y = curve[0].y;
-  right[3].x = curve[3].x;
-  right[3].y = curve[3].y;
-  left[1].x = (curve[0].x + curve[1].x) / 2;
-  left[1].y = (curve[0].y + curve[1].y) / 2;
-  right[2].x = (curve[2].x + curve[3].x) / 2;
-  right[2].y = (curve[2].y + curve[3].y) / 2;
-  left[2].x = left[1].x / 2 + tmp.x;
-  left[2].y = left[1].y / 2 + tmp.y;
-  right[1].x = right[2].x / 2 + tmp.x;
-  right[1].y = right[2].y / 2 + tmp.y;
-  left[3].x = right[0].x = (left[2].x + right[1].x) / 2;
-  left[3].y = right[0].y = (left[2].y + right[1].y) / 2;
-}
-
-static float CalcBezLengthHelper(PathPoint *curve, PRUint32 numPts,
-                                 PRUint32 steps,
-                                 void (*split)(PathPoint*, PathPoint*, PathPoint*))
-{
-  PathPoint left[4];
-  PathPoint right[4];
-  float length = 0, dist;
-  PRUint32 i;
-  for (i = 0; i < numPts - 1; i++) {
-    length += GetDistance(curve[i].x, curve[i+1].x, curve[i].y, curve[i+1].y);
-  }
-  dist = GetDistance(curve[0].x, curve[numPts - 1].x,
-                     curve[0].y, curve[numPts - 1].y);
-  if (length - dist > PATH_SEG_LENGTH_TOLERANCE && steps < MAX_STEPS) {
-      split(curve, left, right);
-      ++steps;
-      return CalcBezLengthHelper(left, numPts, steps, split) + 
-             CalcBezLengthHelper(right, numPts, steps, split);
-  }
-
-  return length;
-}
-
-static inline float CalcBezLength(PathPoint *curve, PRUint32 numPts,
-                                  void (*split)(PathPoint*, PathPoint*, PathPoint*))
-{
-  return CalcBezLengthHelper(curve, numPts, 0, split);
-}
-
-////////////////////////////////////////////////////////////////////////
-// nsSVGPathSeg
-
-nsQueryReferent
-nsSVGPathSeg::GetCurrentList() const
-{
-  return do_QueryReferent(mCurrentList);
-}
-
-nsresult 
-nsSVGPathSeg::SetCurrentList(nsISVGValue* aList)
-{
-  if (!aList) {
-    mCurrentList = nsnull;
-    return NS_OK;
-  }
-  nsresult rv;
-  mCurrentList = do_GetWeakReference(aList, &rv);
-  return rv;
-}
-
-void
-nsSVGPathSeg::DidModify(void)
-{
-  if (mCurrentList) {
-    nsCOMPtr<nsISVGValue> val = do_QueryReferent(mCurrentList);
-    if (val) {
-      val->BeginBatchUpdate();
-      val->EndBatchUpdate();
-    }
-  }
-}
-
-//----------------------------------------------------------------------
-// nsISupports methods:
-
-NS_IMPL_ADDREF(nsSVGPathSeg)
-NS_IMPL_RELEASE(nsSVGPathSeg)
-
-NS_INTERFACE_MAP_BEGIN(nsSVGPathSeg)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMSVGPathSeg)
-  NS_INTERFACE_MAP_ENTRY(nsSVGPathSeg)
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
-NS_INTERFACE_MAP_END
-
-////////////////////////////////////////////////////////////////////////
-// nsSVGPathSegClosePath
-
-class nsSVGPathSegClosePath : public nsIDOMSVGPathSegClosePath,
-                              public nsSVGPathSeg
-{
-public:
-
-  // nsISupports interface:
-  NS_DECL_ISUPPORTS
-
-  // nsIDOMSVGPathSegClosePath interface:
-  NS_DECL_NSIDOMSVGPATHSEGCLOSEPATH
-
-  // nsSVGPathSeg methods:
-  NS_IMETHOD GetValueString(nsAString& aValue);
-  virtual float GetLength(nsSVGPathSegTraversalState *ts);
-  NS_IMPL_SVGPATHSEG(PATHSEG_CLOSEPATH, 'z')
-};
-
-//----------------------------------------------------------------------
-// Implementation
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegClosePath()
-{
-  return new nsSVGPathSegClosePath();
-}
-
-//----------------------------------------------------------------------
-// nsISupports methods:
-NS_IMPL_NSISUPPORTS_SVGPATHSEG(SVGPathSegClosePath)
-
-//----------------------------------------------------------------------
-// nsSVGPathSeg methods:
-NS_IMETHODIMP
-nsSVGPathSegClosePath::GetValueString(nsAString& aValue)
-{
-  aValue.AssignLiteral("z");
-  return NS_OK;
-}
-
-float
-nsSVGPathSegClosePath::GetLength(nsSVGPathSegTraversalState *ts)
-{
-  float dist = GetDistance(ts->startPosX, ts->curPosX,
-                           ts->startPosY, ts->curPosY);
-  ts->quadCPX = ts->cubicCPX = ts->curPosX = ts->startPosX;
-  ts->quadCPY = ts->cubicCPY = ts->curPosY = ts->startPosY;
-  return dist;
-}
-
-////////////////////////////////////////////////////////////////////////
-// nsSVGPathSegMovetoAbs
-
-class nsSVGPathSegMovetoAbs : public nsIDOMSVGPathSegMovetoAbs,
-                              public nsSVGPathSeg
-{
-public:
-  nsSVGPathSegMovetoAbs(float x, float y);
-
-  // nsISupports interface:
-  NS_DECL_ISUPPORTS
-
-  // nsIDOMSVGPathSegMovetoAbs interface:
-  NS_DECL_NSIDOMSVGPATHSEGMOVETOABS
-
-  // nsSVGPathSeg methods:
-  NS_IMETHOD GetValueString(nsAString& aValue);
-  virtual float GetLength(nsSVGPathSegTraversalState *ts);
-  NS_IMPL_SVGPATHSEG(PATHSEG_MOVETO_ABS, 'M')
-
-protected:
-  float mX, mY;
-};
-
-//----------------------------------------------------------------------
-// Implementation
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegMovetoAbs(float x, float y)
-{
-  return new nsSVGPathSegMovetoAbs(x, y);
-}
-
-nsSVGPathSegMovetoAbs::nsSVGPathSegMovetoAbs(float x, float y)
-    : mX(x), mY(y)
-{
-}
-
-//----------------------------------------------------------------------
-// nsISupports methods:
-NS_IMPL_NSISUPPORTS_SVGPATHSEG(SVGPathSegMovetoAbs)
-
-//----------------------------------------------------------------------
-// nsSVGPathSeg methods:
-NS_IMETHODIMP
-nsSVGPathSegMovetoAbs::GetValueString(nsAString& aValue)
-{
-  PRUnichar buf[48];
-  nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar),
-                            NS_LITERAL_STRING("M%g,%g").get(), mX, mY);
-  aValue.Assign(buf);
-
-  return NS_OK;
-}
-
-float
-nsSVGPathSegMovetoAbs::GetLength(nsSVGPathSegTraversalState *ts)
-{
-  ts->cubicCPX = ts->quadCPX = ts->startPosX = ts->curPosX = mX;
-  ts->cubicCPY = ts->quadCPY = ts->startPosY = ts->curPosY = mY;
-  return 0;
-}
-
-//----------------------------------------------------------------------
-// nsIDOMSVGPathSegMovetoAbs methods:
-
-/* attribute float x; */
-NS_IMETHODIMP nsSVGPathSegMovetoAbs::GetX(float *aX)
-{
-  *aX = mX;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegMovetoAbs::SetX(float aX)
-{
-  NS_ENSURE_FINITE(aX, NS_ERROR_ILLEGAL_VALUE);
-  mX = aX;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute float y; */
-NS_IMETHODIMP nsSVGPathSegMovetoAbs::GetY(float *aY)
-{
-  *aY = mY;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegMovetoAbs::SetY(float aY)
-{
-  NS_ENSURE_FINITE(aY, NS_ERROR_ILLEGAL_VALUE);
-  mY = aY;
-  DidModify();
-  return NS_OK;
-}
-
-
-////////////////////////////////////////////////////////////////////////
-// nsSVGPathSegMovetoRel
-
-class nsSVGPathSegMovetoRel : public nsIDOMSVGPathSegMovetoRel,
-                              public nsSVGPathSeg
-{
-public:
-  nsSVGPathSegMovetoRel(float x, float y);
-
-  // nsISupports interface:
-  NS_DECL_ISUPPORTS
-
-  // nsIDOMSVGPathSegMovetoRel interface:
-  NS_DECL_NSIDOMSVGPATHSEGMOVETOREL
-
-  // nsSVGPathSeg methods:
-  NS_IMETHOD GetValueString(nsAString& aValue);
-  virtual float GetLength(nsSVGPathSegTraversalState *ts);
-  NS_IMPL_SVGPATHSEG(PATHSEG_MOVETO_REL, 'm')
-
-protected:
-  float mX, mY;
-};
-
-//----------------------------------------------------------------------
-// Implementation
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegMovetoRel(float x, float y)
-{
-  return new nsSVGPathSegMovetoRel(x, y);
-}
-
-nsSVGPathSegMovetoRel::nsSVGPathSegMovetoRel(float x, float y)
-    : mX(x), mY(y)
-{
-}
-
-//----------------------------------------------------------------------
-// nsISupports methods:
-NS_IMPL_NSISUPPORTS_SVGPATHSEG(SVGPathSegMovetoRel)
-
-//----------------------------------------------------------------------
-// nsSVGPathSeg methods:
-NS_IMETHODIMP
-nsSVGPathSegMovetoRel::GetValueString(nsAString& aValue)
-{
-  PRUnichar buf[48];
-  nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar),
-                            NS_LITERAL_STRING("m%g,%g").get(), mX, mY);
-  aValue.Assign(buf);
-
-  return NS_OK;
-}
-
-float
-nsSVGPathSegMovetoRel::GetLength(nsSVGPathSegTraversalState *ts)
-{
-  ts->cubicCPX = ts->quadCPX = ts->startPosX = ts->curPosX += mX;
-  ts->cubicCPY = ts->quadCPY = ts->startPosY = ts->curPosY += mY;
-  return 0;
-}
-
-//----------------------------------------------------------------------
-// nsIDOMSVGPathSegMovetoRel methods:
-
-/* attribute float x; */
-NS_IMETHODIMP nsSVGPathSegMovetoRel::GetX(float *aX)
-{
-  *aX = mX;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegMovetoRel::SetX(float aX)
-{
-  NS_ENSURE_FINITE(aX, NS_ERROR_ILLEGAL_VALUE);
-  mX = aX;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute float y; */
-NS_IMETHODIMP nsSVGPathSegMovetoRel::GetY(float *aY)
-{
-  *aY = mY;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegMovetoRel::SetY(float aY)
-{
-  NS_ENSURE_FINITE(aY, NS_ERROR_ILLEGAL_VALUE);
-  mY = aY;
-  DidModify();
-  return NS_OK;
-}
-
-////////////////////////////////////////////////////////////////////////
-// nsSVGPathSegLinetoAbs
-
-class nsSVGPathSegLinetoAbs : public nsIDOMSVGPathSegLinetoAbs,
-                              public nsSVGPathSeg
-{
-public:
-  nsSVGPathSegLinetoAbs(float x, float y);
-
-  // nsISupports interface:
-  NS_DECL_ISUPPORTS
-
-  // nsIDOMSVGPathSegLinetoAbs interface:
-  NS_DECL_NSIDOMSVGPATHSEGLINETOABS
-
-  // nsSVGPathSeg methods:
-  NS_IMETHOD GetValueString(nsAString& aValue);
-  virtual float GetLength(nsSVGPathSegTraversalState *ts);
-  NS_IMPL_SVGPATHSEG(PATHSEG_LINETO_ABS, 'L')
-
-protected:
-  float mX, mY;
-};
-
-//----------------------------------------------------------------------
-// Implementation
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegLinetoAbs(float x, float y)
-{
-  return new nsSVGPathSegLinetoAbs(x, y);
-}
-
-nsSVGPathSegLinetoAbs::nsSVGPathSegLinetoAbs(float x, float y)
-    : mX(x), mY(y)
-{
-}
-
-//----------------------------------------------------------------------
-// nsISupports methods:
-NS_IMPL_NSISUPPORTS_SVGPATHSEG(SVGPathSegLinetoAbs)
-
-//----------------------------------------------------------------------
-// nsSVGPathSeg methods:
-NS_IMETHODIMP
-nsSVGPathSegLinetoAbs::GetValueString(nsAString& aValue)
-{
-  PRUnichar buf[48];
-  nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar),
-                            NS_LITERAL_STRING("L%g,%g").get(), mX, mY);
-  aValue.Assign(buf);
-
-  return NS_OK;
-}
-
-float
-nsSVGPathSegLinetoAbs::GetLength(nsSVGPathSegTraversalState *ts)
-{
-  
-  float dist = GetDistance(ts->curPosX, mX, ts->curPosY, mY);
-  ts->cubicCPX = ts->quadCPX = ts->curPosX = mX;
-  ts->cubicCPY = ts->quadCPY = ts->curPosY = mY;
-  return dist;
-}
-
-//----------------------------------------------------------------------
-// nsIDOMSVGPathSegLinetoAbs methods:
-
-/* attribute float x; */
-NS_IMETHODIMP nsSVGPathSegLinetoAbs::GetX(float *aX)
-{
-  *aX = mX;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegLinetoAbs::SetX(float aX)
-{
-  NS_ENSURE_FINITE(aX, NS_ERROR_ILLEGAL_VALUE);
-  mX = aX;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute float y; */
-NS_IMETHODIMP nsSVGPathSegLinetoAbs::GetY(float *aY)
-{
-  *aY = mY;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegLinetoAbs::SetY(float aY)
-{
-  NS_ENSURE_FINITE(aY, NS_ERROR_ILLEGAL_VALUE);
-  mY = aY;
-  DidModify();
-  return NS_OK;
-}
-
-
-////////////////////////////////////////////////////////////////////////
-// nsSVGPathSegLinetoRel
-
-class nsSVGPathSegLinetoRel : public nsIDOMSVGPathSegLinetoRel,
-                              public nsSVGPathSeg
-{
-public:
-  nsSVGPathSegLinetoRel(float x, float y);
-
-  // nsISupports interface:
-  NS_DECL_ISUPPORTS
-
-  // nsIDOMSVGPathSegLinetoRel interface:
-  NS_DECL_NSIDOMSVGPATHSEGLINETOREL
-
-  // nsSVGPathSeg methods:
-  NS_IMETHOD GetValueString(nsAString& aValue);
-  virtual float GetLength(nsSVGPathSegTraversalState *ts);
-  NS_IMPL_SVGPATHSEG(PATHSEG_LINETO_REL, 'l')
-
-protected:
-  float mX, mY;
-};
-
-//----------------------------------------------------------------------
-// Implementation
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegLinetoRel(float x, float y)
-{
-  return new nsSVGPathSegLinetoRel(x, y);
-}
-
-nsSVGPathSegLinetoRel::nsSVGPathSegLinetoRel(float x, float y)
-    : mX(x), mY(y)
-{
-}
-
-//----------------------------------------------------------------------
-// nsISupports methods:
-NS_IMPL_NSISUPPORTS_SVGPATHSEG(SVGPathSegLinetoRel)
-
-//----------------------------------------------------------------------
-// nsSVGPathSeg methods:
-NS_IMETHODIMP
-nsSVGPathSegLinetoRel::GetValueString(nsAString& aValue)
-{
-  PRUnichar buf[48];
-  nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar),
-                            NS_LITERAL_STRING("l%g,%g").get(), mX, mY);
-  aValue.Assign(buf);
-
-  return NS_OK;
-}
-
-float
-nsSVGPathSegLinetoRel::GetLength(nsSVGPathSegTraversalState *ts)
-{
-  ts->cubicCPX = ts->quadCPX = ts->curPosX += mX;
-  ts->cubicCPY = ts->quadCPY = ts->curPosY += mY;
-  return sqrt(mX * mX + mY * mY);
-}
-
-//----------------------------------------------------------------------
-// nsIDOMSVGPathSegLinetoRel methods:
-
-/* attribute float x; */
-NS_IMETHODIMP nsSVGPathSegLinetoRel::GetX(float *aX)
-{
-  *aX = mX;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegLinetoRel::SetX(float aX)
-{
-  NS_ENSURE_FINITE(aX, NS_ERROR_ILLEGAL_VALUE);
-  mX = aX;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute float y; */
-NS_IMETHODIMP nsSVGPathSegLinetoRel::GetY(float *aY)
-{
-  *aY = mY;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegLinetoRel::SetY(float aY)
-{
-  NS_ENSURE_FINITE(aY, NS_ERROR_ILLEGAL_VALUE);
-  mY = aY;
-  DidModify();
-  return NS_OK;
-}
-
-
-////////////////////////////////////////////////////////////////////////
-// nsSVGPathSegCurvetoCubicAbs
-
-class nsSVGPathSegCurvetoCubicAbs : public nsIDOMSVGPathSegCurvetoCubicAbs,
-                                    public nsSVGPathSeg
-{
-public:
-  nsSVGPathSegCurvetoCubicAbs(float x, float y,
-                              float x1, float y1,
-                              float x2, float y2);
-
-  // nsISupports interface:
-  NS_DECL_ISUPPORTS
-
-  // nsIDOMSVGPathSegCurvetoCubicAbs interface:
-  NS_DECL_NSIDOMSVGPATHSEGCURVETOCUBICABS
-
-  // nsSVGPathSeg methods:
-  NS_IMETHOD GetValueString(nsAString& aValue);
-  virtual float GetLength(nsSVGPathSegTraversalState *ts);
-  NS_IMPL_SVGPATHSEG(PATHSEG_CURVETO_CUBIC_ABS, 'C')
-
-protected:
-  float mX, mY, mX1, mY1, mX2, mY2;
-};
-
-//----------------------------------------------------------------------
-// Implementation
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegCurvetoCubicAbs(float x, float y,
-                                float x1, float y1,
-                                float x2, float y2)
-{
-  return new nsSVGPathSegCurvetoCubicAbs(x, y, x1, y1, x2, y2);
-}
-
-nsSVGPathSegCurvetoCubicAbs::nsSVGPathSegCurvetoCubicAbs(float x, float y,
-                                                         float x1, float y1,
-                                                         float x2, float y2)
-    : mX(x), mY(y), mX1(x1), mY1(y1), mX2(x2), mY2(y2)
-{
-}
-
-//----------------------------------------------------------------------
-// nsISupports methods:
-NS_IMPL_NSISUPPORTS_SVGPATHSEG(SVGPathSegCurvetoCubicAbs)
-
-//----------------------------------------------------------------------
-// nsSVGPathSeg methods:
-NS_IMETHODIMP
-nsSVGPathSegCurvetoCubicAbs::GetValueString(nsAString& aValue)
-{
-  PRUnichar buf[144];
-  nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar),
-                            NS_LITERAL_STRING("C%g,%g %g,%g %g,%g").get(), 
-                            mX1, mY1, mX2, mY2, mX, mY);
-  aValue.Assign(buf);
-
-  return NS_OK;
-}
-
-float
-nsSVGPathSegCurvetoCubicAbs::GetLength(nsSVGPathSegTraversalState *ts)
-{
-  PathPoint curve[4] = { {ts->curPosX, ts->curPosY},
-                         {mX1, mY1},
-                         {mX2, mY2},
-                         {mX, mY} };
-  float dist = CalcBezLength(curve, 4, SplitCubicBezier);
-  
-  ts->quadCPX = ts->curPosX = mX;
-  ts->quadCPY = ts->curPosY = mY;
-  ts->cubicCPX = mX2;
-  ts->cubicCPY = mY2;
-  return dist;
-}
-
-//----------------------------------------------------------------------
-// nsIDOMSVGPathSegCurvetoCubicAbs methods:
-
-/* attribute float x; */
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicAbs::GetX(float *aX)
-{
-  *aX = mX;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicAbs::SetX(float aX)
-{
-  NS_ENSURE_FINITE(aX, NS_ERROR_ILLEGAL_VALUE);
-  mX = aX;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute float y; */
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicAbs::GetY(float *aY)
-{
-  *aY = mY;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicAbs::SetY(float aY)
-{
-  NS_ENSURE_FINITE(aY, NS_ERROR_ILLEGAL_VALUE);
-  mY = aY;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute float x1; */
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicAbs::GetX1(float *aX1)
-{
-  *aX1 = mX1;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicAbs::SetX1(float aX1)
-{
-  NS_ENSURE_FINITE(aX1, NS_ERROR_ILLEGAL_VALUE);
-  mX1 = aX1;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute float y1; */
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicAbs::GetY1(float *aY1)
-{
-  *aY1 = mY1;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicAbs::SetY1(float aY1)
-{
-  NS_ENSURE_FINITE(aY1, NS_ERROR_ILLEGAL_VALUE);
-  mY1 = aY1;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute float x2; */
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicAbs::GetX2(float *aX2)
-{
-  *aX2 = mX2;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicAbs::SetX2(float aX2)
-{
-  NS_ENSURE_FINITE(aX2, NS_ERROR_ILLEGAL_VALUE);
-  mX2 = aX2;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute float y2; */
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicAbs::GetY2(float *aY2)
-{
-  *aY2 = mY2;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicAbs::SetY2(float aY2)
-{
-  NS_ENSURE_FINITE(aY2, NS_ERROR_ILLEGAL_VALUE);
-  mY2 = aY2;
-  DidModify();
-  return NS_OK;
-}
-
-
-////////////////////////////////////////////////////////////////////////
-// nsSVGPathSegCurvetoCubicRel
-
-class nsSVGPathSegCurvetoCubicRel : public nsIDOMSVGPathSegCurvetoCubicRel,
-                                    public nsSVGPathSeg
-{
-public:
-  nsSVGPathSegCurvetoCubicRel(float x, float y,
-                              float x1, float y1,
-                              float x2, float y2);
-
-  // nsISupports interface:
-  NS_DECL_ISUPPORTS
-
-  // nsIDOMSVGPathSegCurvetoCubicRel interface:
-  NS_DECL_NSIDOMSVGPATHSEGCURVETOCUBICREL
-
-  // nsSVGPathSeg methods:
-  NS_IMETHOD GetValueString(nsAString& aValue);
-  virtual float GetLength(nsSVGPathSegTraversalState *ts);
-  NS_IMPL_SVGPATHSEG(PATHSEG_CURVETO_CUBIC_REL, 'c')
-
-protected:
-  float mX, mY, mX1, mY1, mX2, mY2;
-};
-
-//----------------------------------------------------------------------
-// Implementation
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegCurvetoCubicRel(float x, float y,
-                                float x1, float y1,
-                                float x2, float y2)
-{
-  return new nsSVGPathSegCurvetoCubicRel(x, y, x1, y1, x2, y2);
-}
-
-nsSVGPathSegCurvetoCubicRel::nsSVGPathSegCurvetoCubicRel(float x, float y,
-                                                         float x1, float y1,
-                                                         float x2, float y2)
-    : mX(x), mY(y), mX1(x1), mY1(y1), mX2(x2), mY2(y2)
-{
-}
-
-//----------------------------------------------------------------------
-// nsISupports methods:
-NS_IMPL_NSISUPPORTS_SVGPATHSEG(SVGPathSegCurvetoCubicRel)
-
-//----------------------------------------------------------------------
-// nsSVGPathSeg methods:
-NS_IMETHODIMP
-nsSVGPathSegCurvetoCubicRel::GetValueString(nsAString& aValue)
-{
-  PRUnichar buf[144];
-  nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar),
-                            NS_LITERAL_STRING("c%g,%g %g,%g %g,%g").get(),
-                            mX1, mY1, mX2, mY2, mX, mY);
-  aValue.Assign(buf);
-
-  return NS_OK;
-}
-
-float
-nsSVGPathSegCurvetoCubicRel::GetLength(nsSVGPathSegTraversalState *ts)
-{
-  PathPoint curve[4] = { {0, 0}, {mX1, mY1}, {mX2, mY2}, {mX, mY} };
-  float dist = CalcBezLength(curve, 4, SplitCubicBezier);
-  
-  ts->cubicCPX = mX2 + ts->curPosX;
-  ts->cubicCPY = mY2 + ts->curPosY;
-  ts->quadCPX = ts->curPosX += mX;
-  ts->quadCPY = ts->curPosY += mY;
-  return dist;
-}
-
-//----------------------------------------------------------------------
-// nsIDOMSVGPathSegCurvetoCubicRel methods:
-
-/* attribute float x; */
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicRel::GetX(float *aX)
-{
-  *aX = mX;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicRel::SetX(float aX)
-{
-  NS_ENSURE_FINITE(aX, NS_ERROR_ILLEGAL_VALUE);
-  mX = aX;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute float y; */
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicRel::GetY(float *aY)
-{
-  *aY = mY;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicRel::SetY(float aY)
-{
-  NS_ENSURE_FINITE(aY, NS_ERROR_ILLEGAL_VALUE);
-  mY = aY;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute float x1; */
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicRel::GetX1(float *aX1)
-{
-  *aX1 = mX1;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicRel::SetX1(float aX1)
-{
-  NS_ENSURE_FINITE(aX1, NS_ERROR_ILLEGAL_VALUE);
-  mX1 = aX1;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute float y1; */
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicRel::GetY1(float *aY1)
-{
-  *aY1 = mY1;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicRel::SetY1(float aY1)
-{
-  NS_ENSURE_FINITE(aY1, NS_ERROR_ILLEGAL_VALUE);
-  mY1 = aY1;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute float x2; */
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicRel::GetX2(float *aX2)
-{
-  *aX2 = mX2;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicRel::SetX2(float aX2)
-{
-  NS_ENSURE_FINITE(aX2, NS_ERROR_ILLEGAL_VALUE);
-  mX2 = aX2;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute float y2; */
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicRel::GetY2(float *aY2)
-{
-  *aY2 = mY2;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicRel::SetY2(float aY2)
-{
-  NS_ENSURE_FINITE(aY2, NS_ERROR_ILLEGAL_VALUE);
-  mY2 = aY2;
-  DidModify();
-  return NS_OK;
-}
-
-////////////////////////////////////////////////////////////////////////
-// nsSVGPathSegCurvetoQuadraticAbs
-
-class nsSVGPathSegCurvetoQuadraticAbs : public nsIDOMSVGPathSegCurvetoQuadraticAbs,
-                                        public nsSVGPathSeg
-{
-public:
-  nsSVGPathSegCurvetoQuadraticAbs(float x, float y,
-                                  float x1, float y1);
-
-  // nsISupports interface:
-  NS_DECL_ISUPPORTS
-
-  // nsIDOMSVGPathSegCurvetoQuadraticAbs interface:
-  NS_DECL_NSIDOMSVGPATHSEGCURVETOQUADRATICABS
-
-  // nsSVGPathSeg methods:
-  NS_IMETHOD GetValueString(nsAString& aValue);
-  virtual float GetLength(nsSVGPathSegTraversalState *ts);
-  NS_IMPL_SVGPATHSEG(PATHSEG_CURVETO_QUADRATIC_ABS, 'Q')
-
-protected:
-  float mX, mY, mX1, mY1;
-};
-
-//----------------------------------------------------------------------
-// Implementation
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegCurvetoQuadraticAbs(float x, float y,
-                                    float x1, float y1)
-{
-  return new nsSVGPathSegCurvetoQuadraticAbs(x, y, x1, y1);
-}
-
-
-nsSVGPathSegCurvetoQuadraticAbs::nsSVGPathSegCurvetoQuadraticAbs(float x, float y,
-                                                                 float x1, float y1)
-    : mX(x), mY(y), mX1(x1), mY1(y1)
-{
-}
-
-//----------------------------------------------------------------------
-// nsISupports methods:
-NS_IMPL_NSISUPPORTS_SVGPATHSEG(SVGPathSegCurvetoQuadraticAbs)
-
-//----------------------------------------------------------------------
-// nsSVGPathSeg methods:
-NS_IMETHODIMP
-nsSVGPathSegCurvetoQuadraticAbs::GetValueString(nsAString& aValue)
-{
-  PRUnichar buf[96];
-  nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar),
-                            NS_LITERAL_STRING("Q%g,%g %g,%g").get(),
-                            mX1, mY1, mX, mY);
-  aValue.Assign(buf);
-
-  return NS_OK;
-}
-
-float
-nsSVGPathSegCurvetoQuadraticAbs::GetLength(nsSVGPathSegTraversalState *ts)
-{
-  PathPoint curve[3] = { {ts->curPosX, ts->curPosY}, {mX1, mY1}, {mX, mY} };
-  float dist = CalcBezLength(curve, 3, SplitQuadraticBezier);
-  
-  ts->quadCPX = mX1;
-  ts->quadCPY = mY1;
-  ts->cubicCPX = ts->curPosX = mX;
-  ts->cubicCPY = ts->curPosY = mY;
-  return dist;
-}
-
-//----------------------------------------------------------------------
-// nsIDOMSVGPathSegCurvetoQuadraticAbs methods:
-
-/* attribute float x; */
-NS_IMETHODIMP nsSVGPathSegCurvetoQuadraticAbs::GetX(float *aX)
-{
-  *aX = mX;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegCurvetoQuadraticAbs::SetX(float aX)
-{
-  NS_ENSURE_FINITE(aX, NS_ERROR_ILLEGAL_VALUE);
-  mX = aX;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute float y; */
-NS_IMETHODIMP nsSVGPathSegCurvetoQuadraticAbs::GetY(float *aY)
-{
-  *aY = mY;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegCurvetoQuadraticAbs::SetY(float aY)
-{
-  NS_ENSURE_FINITE(aY, NS_ERROR_ILLEGAL_VALUE);
-  mY = aY;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute float x1; */
-NS_IMETHODIMP nsSVGPathSegCurvetoQuadraticAbs::GetX1(float *aX1)
-{
-  *aX1 = mX1;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegCurvetoQuadraticAbs::SetX1(float aX1)
-{
-  NS_ENSURE_FINITE(aX1, NS_ERROR_ILLEGAL_VALUE);
-  mX1 = aX1;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute float y1; */
-NS_IMETHODIMP nsSVGPathSegCurvetoQuadraticAbs::GetY1(float *aY1)
-{
-  *aY1 = mY1;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegCurvetoQuadraticAbs::SetY1(float aY1)
-{
-  NS_ENSURE_FINITE(aY1, NS_ERROR_ILLEGAL_VALUE);
-  mY1 = aY1;
-  DidModify();
-  return NS_OK;
-}
-
-
-////////////////////////////////////////////////////////////////////////
-// nsSVGPathSegCurvetoQuadraticRel
-
-class nsSVGPathSegCurvetoQuadraticRel : public nsIDOMSVGPathSegCurvetoQuadraticRel,
-                                        public nsSVGPathSeg
-{
-public:
-  nsSVGPathSegCurvetoQuadraticRel(float x, float y,
-                                  float x1, float y1);
-
-  // nsISupports interface:
-  NS_DECL_ISUPPORTS
-
-  // nsIDOMSVGPathSegCurvetoQuadraticRel interface:
-  NS_DECL_NSIDOMSVGPATHSEGCURVETOQUADRATICREL
-
-  // nsSVGPathSeg methods:
-  NS_IMETHOD GetValueString(nsAString& aValue);
-  virtual float GetLength(nsSVGPathSegTraversalState *ts);
-  NS_IMPL_SVGPATHSEG(PATHSEG_CURVETO_QUADRATIC_REL, 'q')
-
-protected:
-  float mX, mY, mX1, mY1;
-};
-
-//----------------------------------------------------------------------
-// Implementation
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegCurvetoQuadraticRel(float x, float y,
-                                    float x1, float y1)
-{
-  return new nsSVGPathSegCurvetoQuadraticRel(x, y, x1, y1);
-}
-
-
-nsSVGPathSegCurvetoQuadraticRel::nsSVGPathSegCurvetoQuadraticRel(float x, float y,
-                                                                 float x1, float y1)
-    : mX(x), mY(y), mX1(x1), mY1(y1)
-{
-}
-
-//----------------------------------------------------------------------
-// nsISupports methods:
-NS_IMPL_NSISUPPORTS_SVGPATHSEG(SVGPathSegCurvetoQuadraticRel)
-
-//----------------------------------------------------------------------
-// nsSVGPathSeg methods:
-NS_IMETHODIMP
-nsSVGPathSegCurvetoQuadraticRel::GetValueString(nsAString& aValue)
-{
-  PRUnichar buf[96];
-  nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar),
-                            NS_LITERAL_STRING("q%g,%g %g,%g").get(), 
-                            mX1, mY1, mX, mY);
-  aValue.Assign(buf);
-
-  return NS_OK;
-}
-
-float
-nsSVGPathSegCurvetoQuadraticRel::GetLength(nsSVGPathSegTraversalState *ts)
-{
-  PathPoint curve[3] = { {0, 0}, {mX1, mY1}, {mX, mY} };
-  float dist = CalcBezLength(curve, 3, SplitQuadraticBezier);
-  
-  ts->quadCPX = mX1 + ts->curPosX;
-  ts->quadCPY = mY1 + ts->curPosY;
-  ts->cubicCPX = ts->curPosX += mX;
-  ts->cubicCPY = ts->curPosY += mY;
-  return dist;
-}
-
-//----------------------------------------------------------------------
-// nsIDOMSVGPathSegCurvetoQuadraticRel methods:
-
-/* attribute float x; */
-NS_IMETHODIMP nsSVGPathSegCurvetoQuadraticRel::GetX(float *aX)
-{
-  *aX = mX;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegCurvetoQuadraticRel::SetX(float aX)
-{
-  NS_ENSURE_FINITE(aX, NS_ERROR_ILLEGAL_VALUE);
-  mX = aX;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute float y; */
-NS_IMETHODIMP nsSVGPathSegCurvetoQuadraticRel::GetY(float *aY)
-{
-  *aY = mY;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegCurvetoQuadraticRel::SetY(float aY)
-{
-  NS_ENSURE_FINITE(aY, NS_ERROR_ILLEGAL_VALUE);
-  mY = aY;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute float x1; */
-NS_IMETHODIMP nsSVGPathSegCurvetoQuadraticRel::GetX1(float *aX1)
-{
-  *aX1 = mX1;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegCurvetoQuadraticRel::SetX1(float aX1)
-{
-  NS_ENSURE_FINITE(aX1, NS_ERROR_ILLEGAL_VALUE);
-  mX1 = aX1;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute float y1; */
-NS_IMETHODIMP nsSVGPathSegCurvetoQuadraticRel::GetY1(float *aY1)
-{
-  *aY1 = mY1;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegCurvetoQuadraticRel::SetY1(float aY1)
-{
-  NS_ENSURE_FINITE(aY1, NS_ERROR_ILLEGAL_VALUE);
-  mY1 = aY1;
-  DidModify();
-  return NS_OK;
-}
-
-
-////////////////////////////////////////////////////////////////////////
-// nsSVGPathSegArcAbs
-
-class nsSVGPathSegArcAbs : public nsIDOMSVGPathSegArcAbs,
-                           public nsSVGPathSeg
-{
-public:
-  nsSVGPathSegArcAbs(float x, float y,
-                     float r1, float r2, float angle,
-                     PRBool largeArcFlag, PRBool sweepFlag);
-
-  // nsISupports interface:
-  NS_DECL_ISUPPORTS
-
-  // nsIDOMSVGPathSegArcAbs interface:
-  NS_DECL_NSIDOMSVGPATHSEGARCABS
-
-  // nsSVGPathSeg methods:
-  NS_IMETHOD GetValueString(nsAString& aValue);
-  virtual float GetLength(nsSVGPathSegTraversalState *ts);
-  NS_IMPL_SVGPATHSEG(PATHSEG_ARC_ABS, 'A')
-
-protected:
-  float  mX, mY, mR1, mR2, mAngle;
-  PRPackedBool mLargeArcFlag;
-  PRPackedBool mSweepFlag;
-};
-
-//----------------------------------------------------------------------
-// Implementation
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegArcAbs(float x, float y,
-                       float r1, float r2, float angle,
-                       PRBool largeArcFlag, PRBool sweepFlag)
-{
-  return new nsSVGPathSegArcAbs(x, y, r1, r2, angle, largeArcFlag, sweepFlag);
-}
-
-
-nsSVGPathSegArcAbs::nsSVGPathSegArcAbs(float x, float y,
-                                       float r1, float r2, float angle,
-                                       PRBool largeArcFlag, PRBool sweepFlag)
-    : mX(x), mY(y), mR1(r1), mR2(r2), mAngle(angle),
-      mLargeArcFlag(largeArcFlag), mSweepFlag(sweepFlag)
-{
-}
-
-//----------------------------------------------------------------------
-// nsISupports methods:
-NS_IMPL_NSISUPPORTS_SVGPATHSEG(SVGPathSegArcAbs)
-
-//----------------------------------------------------------------------
-// nsSVGPathSeg methods:
-NS_IMETHODIMP
-nsSVGPathSegArcAbs::GetValueString(nsAString& aValue)
-{
-  PRUnichar buf[168];
-  nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar),
-                            NS_LITERAL_STRING("A%g,%g %g %d,%d %g,%g").get(), 
-                            mR1, mR2, mAngle, mLargeArcFlag, mSweepFlag, mX, mY);
-  aValue.Assign(buf);
-
-  return NS_OK;
-}
-
-float
-nsSVGPathSegArcAbs::GetLength(nsSVGPathSegTraversalState *ts)
-{
-  PathPoint bez[4] = { {ts->curPosX, ts->curPosY}, {0,0}, {0,0}, {0,0}};
-  nsSVGArcConverter converter(ts->curPosX, ts->curPosY, mX, mY, mR1,
-                              mR2, mAngle, mLargeArcFlag, mSweepFlag);
-  float dist = 0;
-  while (converter.GetNextSegment(&bez[1].x, &bez[1].y, &bez[2].x, &bez[2].y,
-                                  &bez[3].x, &bez[3].y)) 
-  {
-    dist += CalcBezLength(bez, 4, SplitCubicBezier);
-    bez[0].x = bez[3].x;
-    bez[0].y = bez[3].y;
-  }
-  ts->cubicCPX = ts->quadCPX = ts->curPosX = mX;
-  ts->cubicCPY = ts->quadCPY = ts->curPosY = mY;
-  return dist;
-}
-
-//----------------------------------------------------------------------
-// nsIDOMSVGPathSegArcAbs methods:
-
-/* attribute float x; */
-NS_IMETHODIMP nsSVGPathSegArcAbs::GetX(float *aX)
-{
-  *aX = mX;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegArcAbs::SetX(float aX)
-{
-  NS_ENSURE_FINITE(aX, NS_ERROR_ILLEGAL_VALUE);
-  mX = aX;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute float y; */
-NS_IMETHODIMP nsSVGPathSegArcAbs::GetY(float *aY)
-{
-  *aY = mY;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegArcAbs::SetY(float aY)
-{
-  NS_ENSURE_FINITE(aY, NS_ERROR_ILLEGAL_VALUE);
-  mY = aY;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute float r1; */
-NS_IMETHODIMP nsSVGPathSegArcAbs::GetR1(float *aR1)
-{
-  *aR1 = mR1;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegArcAbs::SetR1(float aR1)
-{
-  NS_ENSURE_FINITE(aR1, NS_ERROR_ILLEGAL_VALUE);
-  mR1 = aR1;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute float r2; */
-NS_IMETHODIMP nsSVGPathSegArcAbs::GetR2(float *aR2)
-{
-  *aR2 = mR2;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegArcAbs::SetR2(float aR2)
-{
-  NS_ENSURE_FINITE(aR2, NS_ERROR_ILLEGAL_VALUE);
-  mR2 = aR2;
-  DidModify();
-  return NS_OK;
-}
-
-
-/* attribute float angle; */
-NS_IMETHODIMP nsSVGPathSegArcAbs::GetAngle(float *aAngle)
-{
-  *aAngle = mAngle;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegArcAbs::SetAngle(float aAngle)
-{
-  NS_ENSURE_FINITE(aAngle, NS_ERROR_ILLEGAL_VALUE);
-  mAngle = aAngle;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute boolean largeArcFlag; */
-NS_IMETHODIMP nsSVGPathSegArcAbs::GetLargeArcFlag(PRBool *aLargeArcFlag)
-{
-  *aLargeArcFlag = mLargeArcFlag;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegArcAbs::SetLargeArcFlag(PRBool aLargeArcFlag)
-{
-  mLargeArcFlag = aLargeArcFlag;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute boolean sweepFlag; */
-NS_IMETHODIMP nsSVGPathSegArcAbs::GetSweepFlag(PRBool *aSweepFlag)
-{
-  *aSweepFlag = mSweepFlag;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegArcAbs::SetSweepFlag(PRBool aSweepFlag)
-{
-  mSweepFlag = aSweepFlag;
-  DidModify();
-  return NS_OK;
-}
-
-////////////////////////////////////////////////////////////////////////
-// nsSVGPathSegArcRel
-
-class nsSVGPathSegArcRel : public nsIDOMSVGPathSegArcRel,
-                           public nsSVGPathSeg
-{
-public:
-  nsSVGPathSegArcRel(float x, float y,
-                     float r1, float r2, float angle,
-                     PRBool largeArcFlag, PRBool sweepFlag);
-
-  // nsISupports interface:
-  NS_DECL_ISUPPORTS
-
-  // nsIDOMSVGPathSegArcRel interface:
-  NS_DECL_NSIDOMSVGPATHSEGARCREL
-
-  // nsSVGPathSeg methods:
-  NS_IMETHOD GetValueString(nsAString& aValue);
-  virtual float GetLength(nsSVGPathSegTraversalState *ts);
-  NS_IMPL_SVGPATHSEG(PATHSEG_ARC_REL, 'a')
-
-protected:
-  float  mX, mY, mR1, mR2, mAngle;
-  PRBool mLargeArcFlag, mSweepFlag;
-};
-
-//----------------------------------------------------------------------
-// Implementation
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegArcRel(float x, float y,
-                       float r1, float r2, float angle,
-                       PRBool largeArcFlag, PRBool sweepFlag)
-{
-  return new nsSVGPathSegArcRel(x, y, r1, r2, angle, largeArcFlag, sweepFlag);
-}
-
-
-nsSVGPathSegArcRel::nsSVGPathSegArcRel(float x, float y,
-                                       float r1, float r2, float angle,
-                                       PRBool largeArcFlag, PRBool sweepFlag)
-    : mX(x), mY(y), mR1(r1), mR2(r2), mAngle(angle),
-      mLargeArcFlag(largeArcFlag), mSweepFlag(sweepFlag)
-{
-}
-
-//----------------------------------------------------------------------
-// nsISupports methods:
-NS_IMPL_NSISUPPORTS_SVGPATHSEG(SVGPathSegArcRel)
-
-//----------------------------------------------------------------------
-// nsSVGPathSeg methods:
-NS_IMETHODIMP
-nsSVGPathSegArcRel::GetValueString(nsAString& aValue)
-{
-  PRUnichar buf[168];
-  nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar),
-                            NS_LITERAL_STRING("a%g,%g %g %d,%d %g,%g").get(), 
-                            mR1, mR2, mAngle, mLargeArcFlag, mSweepFlag, mX, mY);
-  aValue.Assign(buf);
-
-  return NS_OK;
-}
-
-float
-nsSVGPathSegArcRel::GetLength(nsSVGPathSegTraversalState *ts)
-{
-  PathPoint bez[4] = { {0, 0}, {0,0}, {0,0}, {0,0}};
-  nsSVGArcConverter converter(0, 0, mX, mY, mR1, mR2, mAngle,
-                              mLargeArcFlag, mSweepFlag);
-  float dist = 0;
-  while (converter.GetNextSegment(&bez[1].x, &bez[1].y, &bez[2].x, &bez[2].y,
-                                  &bez[3].x, &bez[3].y)) 
-  {
-    dist += CalcBezLength(bez, 4, SplitCubicBezier);
-    bez[0].x = bez[3].x;
-    bez[0].y = bez[3].y;
-  }
-
-  ts->cubicCPX = ts->quadCPX = ts->curPosX += mX;
-  ts->cubicCPY = ts->quadCPY = ts->curPosY += mY;
-  return dist;
-}
-
-//----------------------------------------------------------------------
-// nsIDOMSVGPathSegArcRel methods:
-
-/* attribute float x; */
-NS_IMETHODIMP nsSVGPathSegArcRel::GetX(float *aX)
-{
-  *aX = mX;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegArcRel::SetX(float aX)
-{
-  NS_ENSURE_FINITE(aX, NS_ERROR_ILLEGAL_VALUE);
-  mX = aX;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute float y; */
-NS_IMETHODIMP nsSVGPathSegArcRel::GetY(float *aY)
-{
-  *aY = mY;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegArcRel::SetY(float aY)
-{
-  NS_ENSURE_FINITE(aY, NS_ERROR_ILLEGAL_VALUE);
-  mY = aY;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute float r1; */
-NS_IMETHODIMP nsSVGPathSegArcRel::GetR1(float *aR1)
-{
-  *aR1 = mR1;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegArcRel::SetR1(float aR1)
-{
-  NS_ENSURE_FINITE(aR1, NS_ERROR_ILLEGAL_VALUE);
-  mR1 = aR1;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute float r2; */
-NS_IMETHODIMP nsSVGPathSegArcRel::GetR2(float *aR2)
-{
-  *aR2 = mR2;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegArcRel::SetR2(float aR2)
-{
-  NS_ENSURE_FINITE(aR2, NS_ERROR_ILLEGAL_VALUE);
-  mR2 = aR2;
-  DidModify();
-  return NS_OK;
-}
-
-
-/* attribute float angle; */
-NS_IMETHODIMP nsSVGPathSegArcRel::GetAngle(float *aAngle)
-{
-  *aAngle = mAngle;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegArcRel::SetAngle(float aAngle)
-{
-  NS_ENSURE_FINITE(aAngle, NS_ERROR_ILLEGAL_VALUE);
-  mAngle = aAngle;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute boolean largeArcFlag; */
-NS_IMETHODIMP nsSVGPathSegArcRel::GetLargeArcFlag(PRBool *aLargeArcFlag)
-{
-  *aLargeArcFlag = mLargeArcFlag;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegArcRel::SetLargeArcFlag(PRBool aLargeArcFlag)
-{
-  mLargeArcFlag = aLargeArcFlag;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute boolean sweepFlag; */
-NS_IMETHODIMP nsSVGPathSegArcRel::GetSweepFlag(PRBool *aSweepFlag)
-{
-  *aSweepFlag = mSweepFlag;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegArcRel::SetSweepFlag(PRBool aSweepFlag)
-{
-  mSweepFlag = aSweepFlag;
-  DidModify();
-  return NS_OK;
-}
-
-////////////////////////////////////////////////////////////////////////
-// nsSVGPathSegLinetoHorizontalAbs
-
-class nsSVGPathSegLinetoHorizontalAbs : public nsIDOMSVGPathSegLinetoHorizontalAbs,
-                                        public nsSVGPathSeg
-{
-public:
-  nsSVGPathSegLinetoHorizontalAbs(float x);
-
-  // nsISupports interface:
-  NS_DECL_ISUPPORTS
-
-  // nsIDOMSVGPathSegLinetoHorizontalAbs interface:
-  NS_DECL_NSIDOMSVGPATHSEGLINETOHORIZONTALABS
-
-  // nsSVGPathSeg methods:
-  NS_IMETHOD GetValueString(nsAString& aValue);
-  virtual float GetLength(nsSVGPathSegTraversalState *ts);
-  NS_IMPL_SVGPATHSEG(PATHSEG_LINETO_HORIZONTAL_ABS, 'H')
-
-protected:
-  float mX;
-};
-
-//----------------------------------------------------------------------
-// Implementation
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegLinetoHorizontalAbs(float x)
-{
-  return new nsSVGPathSegLinetoHorizontalAbs(x);
-}
-
-
-nsSVGPathSegLinetoHorizontalAbs::nsSVGPathSegLinetoHorizontalAbs(float x)
-    : mX(x)
-{
-}
-
-//----------------------------------------------------------------------
-// nsISupports methods:
-NS_IMPL_NSISUPPORTS_SVGPATHSEG(SVGPathSegLinetoHorizontalAbs)
-
-//----------------------------------------------------------------------
-// nsSVGPathSeg methods:
-NS_IMETHODIMP
-nsSVGPathSegLinetoHorizontalAbs::GetValueString(nsAString& aValue)
-{
-  PRUnichar buf[24];
-  nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar),
-                            NS_LITERAL_STRING("H%g").get(), mX);
-  aValue.Assign(buf);
-
-  return NS_OK;
-}
-
-float
-nsSVGPathSegLinetoHorizontalAbs::GetLength(nsSVGPathSegTraversalState *ts)
-{
-  float dist = fabs(mX - ts->curPosX);
-  ts->cubicCPX = ts->quadCPX = ts->curPosX = mX;
-  ts->cubicCPY = ts->quadCPY = ts->curPosY;
-  return dist;
-}
-
-//----------------------------------------------------------------------
-// nsIDOMSVGPathSegLinetoHorizontalAbs methods:
-
-/* attribute float x; */
-NS_IMETHODIMP nsSVGPathSegLinetoHorizontalAbs::GetX(float *aX)
-{
-  *aX = mX;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegLinetoHorizontalAbs::SetX(float aX)
-{
-  NS_ENSURE_FINITE(aX, NS_ERROR_ILLEGAL_VALUE);
-  mX = aX;
-  DidModify();
-  return NS_OK;
-}
-
-////////////////////////////////////////////////////////////////////////
-// nsSVGPathSegLinetoHorizontalRel
-
-class nsSVGPathSegLinetoHorizontalRel : public nsIDOMSVGPathSegLinetoHorizontalRel,
-                                        public nsSVGPathSeg
-{
-public:
-  nsSVGPathSegLinetoHorizontalRel(float x);
-
-  // nsISupports interface:
-  NS_DECL_ISUPPORTS
-
-  // nsIDOMSVGPathSegLinetoHorizontalRel interface:
-  NS_DECL_NSIDOMSVGPATHSEGLINETOHORIZONTALREL
-
-  // nsSVGPathSeg methods:
-  NS_IMETHOD GetValueString(nsAString& aValue);
-  virtual float GetLength(nsSVGPathSegTraversalState *ts);
-  NS_IMPL_SVGPATHSEG(PATHSEG_LINETO_HORIZONTAL_REL, 'h')
-
-protected:
-  float mX;
-};
-
-//----------------------------------------------------------------------
-// Implementation
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegLinetoHorizontalRel(float x)
-{
-  return new nsSVGPathSegLinetoHorizontalRel(x);
-}
-
-
-nsSVGPathSegLinetoHorizontalRel::nsSVGPathSegLinetoHorizontalRel(float x)
-    : mX(x)
-{
-}
-
-//----------------------------------------------------------------------
-// nsISupports methods:
-NS_IMPL_NSISUPPORTS_SVGPATHSEG(SVGPathSegLinetoHorizontalRel)
-
-//----------------------------------------------------------------------
-// nsSVGPathSeg methods:
-NS_IMETHODIMP
-nsSVGPathSegLinetoHorizontalRel::GetValueString(nsAString& aValue)
-{
-  PRUnichar buf[24];
-  nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar),
-                            NS_LITERAL_STRING("h%g").get(), mX);
-  aValue.Assign(buf);
-
-  return NS_OK;
-}
-
-float
-nsSVGPathSegLinetoHorizontalRel::GetLength(nsSVGPathSegTraversalState *ts)
-{
-  ts->cubicCPX = ts->quadCPX = ts->curPosX += mX;
-  ts->cubicCPY = ts->quadCPY = ts->curPosY;
-  return fabs(mX);
-}
-
-//----------------------------------------------------------------------
-// nsIDOMSVGPathSegLinetoHorizontalRel methods:
-
-/* attribute float x; */
-NS_IMETHODIMP nsSVGPathSegLinetoHorizontalRel::GetX(float *aX)
-{
-  *aX = mX;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegLinetoHorizontalRel::SetX(float aX)
-{
-  NS_ENSURE_FINITE(aX, NS_ERROR_ILLEGAL_VALUE);
-  mX = aX;
-  DidModify();
-  return NS_OK;
-}
-
-////////////////////////////////////////////////////////////////////////
-// nsSVGPathSegLinetoVerticalAbs
-
-class nsSVGPathSegLinetoVerticalAbs : public nsIDOMSVGPathSegLinetoVerticalAbs,
-                                      public nsSVGPathSeg
-{
-public:
-  nsSVGPathSegLinetoVerticalAbs(float y);
-
-  // nsISupports interface:
-  NS_DECL_ISUPPORTS
-
-  // nsIDOMSVGPathSegLinetoVerticalAbs interface:
-  NS_DECL_NSIDOMSVGPATHSEGLINETOVERTICALABS
-
-  // nsSVGPathSeg methods:
-  NS_IMETHOD GetValueString(nsAString& aValue);
-  virtual float GetLength(nsSVGPathSegTraversalState *ts);
-  NS_IMPL_SVGPATHSEG(PATHSEG_LINETO_VERTICAL_ABS, 'V')
-
-protected:
-  float mY;
-};
-
-//----------------------------------------------------------------------
-// Implementation
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegLinetoVerticalAbs(float y)
-{
-  return new nsSVGPathSegLinetoVerticalAbs(y);
-}
-
-
-nsSVGPathSegLinetoVerticalAbs::nsSVGPathSegLinetoVerticalAbs(float y)
-    : mY(y)
-{
-}
-
-//----------------------------------------------------------------------
-// nsISupports methods:
-NS_IMPL_NSISUPPORTS_SVGPATHSEG(SVGPathSegLinetoVerticalAbs)
-
-//----------------------------------------------------------------------
-// nsSVGPathSeg methods:
-NS_IMETHODIMP
-nsSVGPathSegLinetoVerticalAbs::GetValueString(nsAString& aValue)
-{
-  PRUnichar buf[24];
-  nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar),
-                            NS_LITERAL_STRING("V%g").get(), mY);
-  aValue.Assign(buf);
-
-  return NS_OK;
-}
-
-float
-nsSVGPathSegLinetoVerticalAbs::GetLength(nsSVGPathSegTraversalState *ts)
-{
-  float dist = fabs(mY - ts->curPosY);
-  ts->cubicCPY = ts->quadCPY = ts->curPosY = mY;
-  ts->cubicCPX = ts->quadCPX = ts->curPosX;
-  return dist;
-}
-
-//----------------------------------------------------------------------
-// nsIDOMSVGPathSegLinetoVerticalAbs methods:
-
-/* attribute float y; */
-NS_IMETHODIMP nsSVGPathSegLinetoVerticalAbs::GetY(float *aY)
-{
-  *aY = mY;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegLinetoVerticalAbs::SetY(float aY)
-{
-  NS_ENSURE_FINITE(aY, NS_ERROR_ILLEGAL_VALUE);
-  mY = aY;
-  DidModify();
-  return NS_OK;
-}
-
-////////////////////////////////////////////////////////////////////////
-// nsSVGPathSegLinetoVerticalRel
-
-class nsSVGPathSegLinetoVerticalRel : public nsIDOMSVGPathSegLinetoVerticalRel,
-                                      public nsSVGPathSeg
-{
-public:
-  nsSVGPathSegLinetoVerticalRel(float y);
-
-  // nsISupports interface:
-  NS_DECL_ISUPPORTS
-
-  // nsIDOMSVGPathSegLinetoVerticalRel interface:
-  NS_DECL_NSIDOMSVGPATHSEGLINETOVERTICALREL
-
-  // nsSVGPathSeg methods:
-  NS_IMETHOD GetValueString(nsAString& aValue);
-  virtual float GetLength(nsSVGPathSegTraversalState *ts);
-  NS_IMPL_SVGPATHSEG(PATHSEG_LINETO_VERTICAL_REL, 'v')
-
-protected:
-  float mY;
-};
-
-//----------------------------------------------------------------------
-// Implementation
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegLinetoVerticalRel(float y)
-{
-  return new nsSVGPathSegLinetoVerticalRel(y);
-}
-
-
-nsSVGPathSegLinetoVerticalRel::nsSVGPathSegLinetoVerticalRel(float y)
-    : mY(y)
-{
-}
-
-//----------------------------------------------------------------------
-// nsISupports methods:
-NS_IMPL_NSISUPPORTS_SVGPATHSEG(SVGPathSegLinetoVerticalRel)
-
-//----------------------------------------------------------------------
-// nsSVGPathSeg methods:
-NS_IMETHODIMP
-nsSVGPathSegLinetoVerticalRel::GetValueString(nsAString& aValue)
-{
-  PRUnichar buf[24];
-  nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar),
-                            NS_LITERAL_STRING("v%g").get(), mY);
-  aValue.Assign(buf);
-
-  return NS_OK;
-}
-
-float
-nsSVGPathSegLinetoVerticalRel::GetLength(nsSVGPathSegTraversalState *ts)
-{
-  ts->cubicCPY = ts->quadCPY = ts->curPosY += mY;
-  ts->cubicCPX = ts->quadCPX = ts->curPosX;
-  return fabs(mY);
-}
-
-//----------------------------------------------------------------------
-// nsIDOMSVGPathSegLinetoVerticalRel methods:
-
-/* attribute float y; */
-NS_IMETHODIMP nsSVGPathSegLinetoVerticalRel::GetY(float *aY)
-{
-  *aY = mY;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegLinetoVerticalRel::SetY(float aY)
-{
-  NS_ENSURE_FINITE(aY, NS_ERROR_ILLEGAL_VALUE);
-  mY = aY;
-  DidModify();
-  return NS_OK;
-}
-
-////////////////////////////////////////////////////////////////////////
-// nsSVGPathSegCurvetoCubicSmoothAbs
-
-class nsSVGPathSegCurvetoCubicSmoothAbs : public nsIDOMSVGPathSegCurvetoCubicSmoothAbs,
-                                          public nsSVGPathSeg
-{
-public:
-  nsSVGPathSegCurvetoCubicSmoothAbs(float x, float y,
-                                    float x2, float y2);
-
-  // nsISupports interface:
-  NS_DECL_ISUPPORTS
-
-  // nsIDOMSVGPathSegCurvetoCubicSmoothAbs interface:
-  NS_DECL_NSIDOMSVGPATHSEGCURVETOCUBICSMOOTHABS
-
-  // nsSVGPathSeg methods:
-  NS_IMETHOD GetValueString(nsAString& aValue);
-  virtual float GetLength(nsSVGPathSegTraversalState *ts);
-  NS_IMPL_SVGPATHSEG(PATHSEG_CURVETO_CUBIC_SMOOTH_ABS, 'S')
-
-protected:
-  float mX, mY, mX2, mY2;
-};
-
-//----------------------------------------------------------------------
-// Implementation
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegCurvetoCubicSmoothAbs(float x, float y,
-                                      float x2, float y2)
-{
-  return new nsSVGPathSegCurvetoCubicSmoothAbs(x, y, x2, y2);
-}
-
-
-nsSVGPathSegCurvetoCubicSmoothAbs::nsSVGPathSegCurvetoCubicSmoothAbs(float x, float y,
-                                                                     float x2, float y2)
-    : mX(x), mY(y), mX2(x2), mY2(y2)
-{
-}
-
-//----------------------------------------------------------------------
-// nsISupports methods:
-NS_IMPL_NSISUPPORTS_SVGPATHSEG(SVGPathSegCurvetoCubicSmoothAbs)
-
-//----------------------------------------------------------------------
-// nsSVGPathSeg methods:
-NS_IMETHODIMP
-nsSVGPathSegCurvetoCubicSmoothAbs::GetValueString(nsAString& aValue)
-{
-  PRUnichar buf[96];
-  nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar),
-                            NS_LITERAL_STRING("S%g,%g %g,%g").get(),
-                            mX2, mY2, mX, mY);
-  aValue.Assign(buf);
-
-  return NS_OK;
-}
-
-float
-nsSVGPathSegCurvetoCubicSmoothAbs::GetLength(nsSVGPathSegTraversalState *ts)
-{
-  float x1 = 2 * ts->curPosX - ts->cubicCPX;
-  float y1 = 2 * ts->curPosY - ts->cubicCPY;
-
-  PathPoint curve[4] = { {ts->curPosX, ts->curPosY},
-                         {x1, y1},
-                         {mX2, mY2},
-                         {mX, mY} };
-  float dist = CalcBezLength(curve, 4, SplitCubicBezier);
-
-  ts->cubicCPX = mX2;
-  ts->cubicCPY = mY2;
-  ts->quadCPX = ts->curPosX = mX;
-  ts->quadCPY = ts->curPosY = mY;
-  return dist;
-}
-
-//----------------------------------------------------------------------
-// nsIDOMSVGPathSegCurvetoCubicSmoothAbs methods:
-
-/* attribute float x; */
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicSmoothAbs::GetX(float *aX)
-{
-  *aX = mX;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicSmoothAbs::SetX(float aX)
-{
-  NS_ENSURE_FINITE(aX, NS_ERROR_ILLEGAL_VALUE);
-  mX = aX;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute float y; */
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicSmoothAbs::GetY(float *aY)
-{
-  *aY = mY;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicSmoothAbs::SetY(float aY)
-{
-  NS_ENSURE_FINITE(aY, NS_ERROR_ILLEGAL_VALUE);
-  mY = aY;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute float x2; */
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicSmoothAbs::GetX2(float *aX2)
-{
-  *aX2 = mX2;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicSmoothAbs::SetX2(float aX2)
-{
-  NS_ENSURE_FINITE(aX2, NS_ERROR_ILLEGAL_VALUE);
-  mX2 = aX2;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute float y2; */
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicSmoothAbs::GetY2(float *aY2)
-{
-  *aY2 = mY2;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicSmoothAbs::SetY2(float aY2)
-{
-  NS_ENSURE_FINITE(aY2, NS_ERROR_ILLEGAL_VALUE);
-  mY2 = aY2;
-  DidModify();
-  return NS_OK;
-}
-
-////////////////////////////////////////////////////////////////////////
-// nsSVGPathSegCurvetoCubicSmoothRel
-
-class nsSVGPathSegCurvetoCubicSmoothRel : public nsIDOMSVGPathSegCurvetoCubicSmoothRel,
-                                          public nsSVGPathSeg
-{
-public:
-  nsSVGPathSegCurvetoCubicSmoothRel(float x, float y,
-                                    float x2, float y2);
-
-  // nsISupports interface:
-  NS_DECL_ISUPPORTS
-
-  // nsIDOMSVGPathSegCurvetoCubicSmoothRel interface:
-  NS_DECL_NSIDOMSVGPATHSEGCURVETOCUBICSMOOTHREL
-
-  // nsSVGPathSeg methods:
-  NS_IMETHOD GetValueString(nsAString& aValue);
-  virtual float GetLength(nsSVGPathSegTraversalState *ts);
-  NS_IMPL_SVGPATHSEG(PATHSEG_CURVETO_CUBIC_SMOOTH_REL, 's')
-
-protected:
-  float mX, mY, mX2, mY2;
-};
-
-//----------------------------------------------------------------------
-// Implementation
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegCurvetoCubicSmoothRel(float x, float y,
-                                      float x2, float y2)
-{
-  return new nsSVGPathSegCurvetoCubicSmoothRel(x, y, x2, y2);
-}
-
-
-nsSVGPathSegCurvetoCubicSmoothRel::nsSVGPathSegCurvetoCubicSmoothRel(float x, float y,
-                                                                     float x2, float y2)
-    : mX(x), mY(y), mX2(x2), mY2(y2)
-{
-}
-
-//----------------------------------------------------------------------
-// nsISupports methods:
-NS_IMPL_NSISUPPORTS_SVGPATHSEG(SVGPathSegCurvetoCubicSmoothRel)
-
-//----------------------------------------------------------------------
-// nsSVGPathSeg methods:
-NS_IMETHODIMP
-nsSVGPathSegCurvetoCubicSmoothRel::GetValueString(nsAString& aValue)
-{
-  PRUnichar buf[96];
-  nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar),
-                            NS_LITERAL_STRING("s%g,%g %g,%g").get(),
-                            mX2, mY2, mX, mY);
-  aValue.Assign(buf);
-
-  return NS_OK;
-}
-
-float
-nsSVGPathSegCurvetoCubicSmoothRel::GetLength(nsSVGPathSegTraversalState *ts)
-{
-  
-  float x1 = ts->curPosX - ts->cubicCPX;
-  float y1 = ts->curPosY - ts->cubicCPY;
-
-  PathPoint curve[4] = { {0, 0}, {x1, y1}, {mX2, mY2}, {mX, mY} };
-  float dist = CalcBezLength(curve, 4, SplitCubicBezier);
-
-  ts->cubicCPX = mX2 + ts->curPosX;
-  ts->cubicCPY = mY2 + ts->curPosY;
-  ts->quadCPX = ts->curPosX += mX;
-  ts->quadCPY = ts->curPosY += mY;
-  return dist;
-}
-
-//----------------------------------------------------------------------
-// nsIDOMSVGPathSegCurvetoCubicSmoothRel methods:
-
-/* attribute float x; */
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicSmoothRel::GetX(float *aX)
-{
-  *aX = mX;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicSmoothRel::SetX(float aX)
-{
-  NS_ENSURE_FINITE(aX, NS_ERROR_ILLEGAL_VALUE);
-  mX = aX;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute float y; */
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicSmoothRel::GetY(float *aY)
-{
-  *aY = mY;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicSmoothRel::SetY(float aY)
-{
-  NS_ENSURE_FINITE(aY, NS_ERROR_ILLEGAL_VALUE);
-  mY = aY;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute float x2; */
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicSmoothRel::GetX2(float *aX2)
-{
-  *aX2 = mX2;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicSmoothRel::SetX2(float aX2)
-{
-  NS_ENSURE_FINITE(aX2, NS_ERROR_ILLEGAL_VALUE);
-  mX2 = aX2;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute float y2; */
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicSmoothRel::GetY2(float *aY2)
-{
-  *aY2 = mY2;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegCurvetoCubicSmoothRel::SetY2(float aY2)
-{
-  NS_ENSURE_FINITE(aY2, NS_ERROR_ILLEGAL_VALUE);
-  mY2 = aY2;
-  DidModify();
-  return NS_OK;
-}
-
-////////////////////////////////////////////////////////////////////////
-// nsSVGPathSegCurvetoQuadraticSmoothAbs
-
-class nsSVGPathSegCurvetoQuadraticSmoothAbs : public nsIDOMSVGPathSegCurvetoQuadraticSmoothAbs,
-                                              public nsSVGPathSeg
-{
-public:
-  nsSVGPathSegCurvetoQuadraticSmoothAbs(float x, float y);
-
-  // nsISupports interface:
-  NS_DECL_ISUPPORTS
-
-  // nsIDOMSVGPathSegCurvetoQuadraticSmoothAbs interface:
-  NS_DECL_NSIDOMSVGPATHSEGCURVETOQUADRATICSMOOTHABS
-
-  // nsSVGPathSeg methods:
-  NS_IMETHOD GetValueString(nsAString& aValue);
-  virtual float GetLength(nsSVGPathSegTraversalState *ts);
-  NS_IMPL_SVGPATHSEG(PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS, 'T')
-
-protected:
-  float mX, mY;
-};
-
-//----------------------------------------------------------------------
-// Implementation
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegCurvetoQuadraticSmoothAbs(float x, float y)
-{
-  return new nsSVGPathSegCurvetoQuadraticSmoothAbs(x, y);
-}
-
-nsSVGPathSegCurvetoQuadraticSmoothAbs::nsSVGPathSegCurvetoQuadraticSmoothAbs(float x, float y)
-    : mX(x), mY(y)
-{
-}
-
-//----------------------------------------------------------------------
-// nsISupports methods:
-NS_IMPL_NSISUPPORTS_SVGPATHSEG(SVGPathSegCurvetoQuadraticSmoothAbs)
-
-//----------------------------------------------------------------------
-// nsSVGPathSeg methods:
-NS_IMETHODIMP
-nsSVGPathSegCurvetoQuadraticSmoothAbs::GetValueString(nsAString& aValue)
-{
-  PRUnichar buf[48];
-  nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar),
-                            NS_LITERAL_STRING("T%g,%g").get(), mX, mY);
-  aValue.Assign(buf);
-
-  return NS_OK;
-}
-
-float
-nsSVGPathSegCurvetoQuadraticSmoothAbs::GetLength(nsSVGPathSegTraversalState *ts)
-{
-  ts->quadCPX = 2 * ts->curPosX - ts->quadCPX;
-  ts->quadCPY = 2 * ts->curPosY - ts->quadCPY;
-
-  PathPoint bez[3] = { {ts->curPosX, ts->curPosY},
-                       {ts->quadCPX, ts->quadCPY},
-                       {mX, mY} };
-  float dist = CalcBezLength(bez, 3, SplitQuadraticBezier);
-
-  ts->cubicCPX = ts->curPosX = mX;
-  ts->cubicCPY = ts->curPosY = mY;
-  return dist;
-}
-
-//----------------------------------------------------------------------
-// nsIDOMSVGPathSegCurvetoQuadraticSmoothAbs methods:
-
-/* attribute float x; */
-NS_IMETHODIMP nsSVGPathSegCurvetoQuadraticSmoothAbs::GetX(float *aX)
-{
-  *aX = mX;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegCurvetoQuadraticSmoothAbs::SetX(float aX)
-{
-  NS_ENSURE_FINITE(aX, NS_ERROR_ILLEGAL_VALUE);
-  mX = aX;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute float y; */
-NS_IMETHODIMP nsSVGPathSegCurvetoQuadraticSmoothAbs::GetY(float *aY)
-{
-  *aY = mY;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegCurvetoQuadraticSmoothAbs::SetY(float aY)
-{
-  NS_ENSURE_FINITE(aY, NS_ERROR_ILLEGAL_VALUE);
-  mY = aY;
-  DidModify();
-  return NS_OK;
-}
-
-////////////////////////////////////////////////////////////////////////
-// nsSVGPathSegCurvetoQuadraticSmoothRel
-
-class nsSVGPathSegCurvetoQuadraticSmoothRel : public nsIDOMSVGPathSegCurvetoQuadraticSmoothRel,
-                                              public nsSVGPathSeg
-{
-public:
-  nsSVGPathSegCurvetoQuadraticSmoothRel(float x, float y);
-
-  // nsISupports interface:
-  NS_DECL_ISUPPORTS
-
-  // nsIDOMSVGPathSegCurvetoQuadraticSmoothRel interface:
-  NS_DECL_NSIDOMSVGPATHSEGCURVETOQUADRATICSMOOTHREL
-
-  // nsSVGPathSeg methods:
-  NS_IMETHOD GetValueString(nsAString& aValue);
-  virtual float GetLength(nsSVGPathSegTraversalState *ts);
-  NS_IMPL_SVGPATHSEG(PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL, 't')
-
-protected:
-  float mX, mY;
-};
-
-//----------------------------------------------------------------------
-// Implementation
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegCurvetoQuadraticSmoothRel(float x, float y)
-{
-  return new nsSVGPathSegCurvetoQuadraticSmoothRel(x, y);
-}
-
-
-nsSVGPathSegCurvetoQuadraticSmoothRel::nsSVGPathSegCurvetoQuadraticSmoothRel(float x, float y)
-    : mX(x), mY(y)
-{
-}
-
-//----------------------------------------------------------------------
-// nsISupports methods:
-NS_IMPL_NSISUPPORTS_SVGPATHSEG(SVGPathSegCurvetoQuadraticSmoothRel)
-
-//----------------------------------------------------------------------
-// nsSVGPathSeg methods:
-NS_IMETHODIMP
-nsSVGPathSegCurvetoQuadraticSmoothRel::GetValueString(nsAString& aValue)
-{
-  PRUnichar buf[24];
-  nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar),
-                            NS_LITERAL_STRING("t%g,%g").get(), mX, mY);
-  aValue.Assign(buf);
-
-  return NS_OK;
-}
-
-float
-nsSVGPathSegCurvetoQuadraticSmoothRel::GetLength(nsSVGPathSegTraversalState *ts)
-{
-  ts->quadCPX = ts->curPosX - ts->quadCPX;
-  ts->quadCPY = ts->curPosY - ts->quadCPY;
-
-  PathPoint bez[3] = { {0, 0}, {ts->quadCPX, ts->quadCPY}, {mX, mY} };
-  float dist = CalcBezLength(bez, 3, SplitQuadraticBezier);
-
-  ts->quadCPX += ts->curPosX;
-  ts->quadCPY += ts->curPosY;
-
-  ts->cubicCPX = ts->curPosX += mX;
-  ts->cubicCPY = ts->curPosY += mY;
-  return dist;
-}
-
-//----------------------------------------------------------------------
-// nsIDOMSVGPathSegCurvetoQuadraticSmoothRel methods:
-
-/* attribute float x; */
-NS_IMETHODIMP nsSVGPathSegCurvetoQuadraticSmoothRel::GetX(float *aX)
-{
-  *aX = mX;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegCurvetoQuadraticSmoothRel::SetX(float aX)
-{
-  NS_ENSURE_FINITE(aX, NS_ERROR_ILLEGAL_VALUE);
-  mX = aX;
-  DidModify();
-  return NS_OK;
-}
-
-/* attribute float y; */
-NS_IMETHODIMP nsSVGPathSegCurvetoQuadraticSmoothRel::GetY(float *aY)
-{
-  *aY = mY;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPathSegCurvetoQuadraticSmoothRel::SetY(float aY)
-{
-  NS_ENSURE_FINITE(aY, NS_ERROR_ILLEGAL_VALUE);
-  mY = aY;
-  DidModify();
-  return NS_OK;
-}
-
deleted file mode 100644
--- a/content/svg/content/src/nsSVGPathSeg.h
+++ /dev/null
@@ -1,173 +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_SVGPATHSEG_H__
-#define __NS_SVGPATHSEG_H__
-
-#include "nsIDOMSVGPathSeg.h"
-#include "nsIWeakReference.h"
-#include "nsSVGUtils.h"
-#include "nsSVGPathDataParser.h"
-
-// 0dfd1b3c-5638-4813-a6f8-5a325a35d06e
-#define NS_SVGPATHSEG_IID \
-  { 0x0dfd1b3c, 0x5638, 0x4813, \
-    { 0xa6, 0xf8, 0x5a, 0x32, 0x5a, 0x35, 0xd0, 0x6e } }
-
-#define NS_ENSURE_NATIVE_PATH_SEG(obj, retval)            \
-  {                                                       \
-    nsCOMPtr<nsSVGPathSeg> path = do_QueryInterface(obj); \
-    if (!path) {                                          \
-      *retval = nsnull;                                   \
-      return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;             \
-    }                                                     \
-  }
-
-class nsSVGPathSegList;
-class nsISVGValue;
-
-struct nsSVGPathSegTraversalState {
-  float curPosX, startPosX, quadCPX, cubicCPX;
-  float curPosY, startPosY, quadCPY, cubicCPY;
-  nsSVGPathSegTraversalState()
-  {
-    curPosX = startPosX = quadCPX = cubicCPX = 0;
-    curPosY = startPosY = quadCPY = cubicCPY = 0;
-  }
-};
-
-class nsSVGPathSeg : public nsIDOMSVGPathSeg
-{
-public:
-  NS_DECLARE_STATIC_IID_ACCESSOR(NS_SVGPATHSEG_IID)
-
-  nsSVGPathSeg() : mCurrentList(nsnull) {}
-  nsresult SetCurrentList(nsISVGValue* aList);
-  nsQueryReferent GetCurrentList() const;
-
-  // nsISupports interface:
-  NS_DECL_ISUPPORTS
-
-  // nsIDOMSVGPathSeg interface:
-  NS_IMETHOD GetPathSegType(PRUint16 *aPathSegType) = 0;
-  NS_IMETHOD GetPathSegTypeAsLetter(nsAString & aPathSegTypeAsLetter) = 0;
-
-  // nsSVGPathSeg methods:
-  NS_IMETHOD GetValueString(nsAString& aValue) = 0;
-  virtual float GetLength(nsSVGPathSegTraversalState *ts) = 0;
-
-protected:
-  void DidModify();
-
-private:
-  nsCOMPtr<nsIWeakReference> mCurrentList;
-};
-
-NS_DEFINE_STATIC_IID_ACCESSOR(nsSVGPathSeg, NS_SVGPATHSEG_IID)
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegClosePath();
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegMovetoAbs(float x, float y);
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegMovetoRel(float x, float y);
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegLinetoAbs(float x, float y);
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegLinetoRel(float x, float y);
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegCurvetoCubicAbs(float x, float y,
-                                float x1, float y1,
-                                float x2, float y2);
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegCurvetoCubicRel(float x, float y,
-                                float x1, float y1,
-                                float x2, float y2);
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegCurvetoQuadraticAbs(float x, float y,
-                                    float x1, float y1);
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegCurvetoQuadraticRel(float x, float y,
-                                    float x1, float y1);
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegArcAbs(float x, float y,
-                       float r1, float r2, float angle,
-                       PRBool largeArcFlag, PRBool sweepFlag);
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegArcRel(float x, float y,
-                       float r1, float r2, float angle,
-                       PRBool largeArcFlag, PRBool sweepFlag);
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegLinetoHorizontalAbs(float x);
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegLinetoHorizontalRel(float x);
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegLinetoVerticalAbs(float y);
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegLinetoVerticalRel(float y);
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegCurvetoCubicSmoothAbs(float x, float y,
-                                      float x2, float y2);
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegCurvetoCubicSmoothRel(float x, float y,
-                                      float x2, float y2);
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegCurvetoQuadraticSmoothAbs(float x, float y);
-
-nsIDOMSVGPathSeg*
-NS_NewSVGPathSegCurvetoQuadraticSmoothRel(float x, float y);
-
-
-#endif //__NS_SVGPATHSEG_H__
deleted file mode 100644
--- a/content/svg/content/src/nsSVGPathSegList.cpp
+++ /dev/null
@@ -1,400 +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 "nsSVGPathSegList.h"
-#include "nsSVGPathSeg.h"
-#include "nsSVGValue.h"
-#include "nsWeakReference.h"
-#include "nsCOMArray.h"
-#include "nsDOMError.h"
-#include "nsSVGPathDataParser.h"
-#include "nsReadableUtils.h"
-#include "nsContentUtils.h"
-
-////////////////////////////////////////////////////////////////////////
-// nsSVGPathSegList
-
-class nsSVGPathSegList : public nsIDOMSVGPathSegList,
-                         public nsSVGValue,
-                         public nsISVGValueObserver
-{  
-protected:
-  friend nsresult NS_NewSVGPathSegList(nsIDOMSVGPathSegList** result);
-
-  nsSVGPathSegList();
-  ~nsSVGPathSegList();
-//  void Init();
-
-public:
-  // nsISupports interface:
-  NS_DECL_ISUPPORTS
-
-  // nsIDOMSVGPathSegList interface:
-  NS_DECL_NSIDOMSVGPATHSEGLIST
-
-  // 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
-
-protected:
-  // implementation helpers:
-  void AppendElement(nsSVGPathSeg* aElement);
-  void RemoveElementAt(PRInt32 index);
-  void InsertElementAt(nsSVGPathSeg* aElement, PRInt32 index);
-  void RemoveFromCurrentList(nsSVGPathSeg*);
-
-  void ReleaseSegments(PRBool aModify = PR_TRUE);
-
-  nsCOMArray<nsIDOMSVGPathSeg> mSegments;
-};
-
-
-//----------------------------------------------------------------------
-// Implementation
-
-nsSVGPathSegList::nsSVGPathSegList()
-{
-}
-
-nsSVGPathSegList::~nsSVGPathSegList()
-{
-  PRInt32 count = mSegments.Count();
-  for (PRInt32 i = 0; i < count; ++i) {
-    nsSVGPathSeg* seg = static_cast<nsSVGPathSeg*>(mSegments.ObjectAt(i));
-    seg->SetCurrentList(nsnull);
-  }
-}
-
-//----------------------------------------------------------------------
-// nsISupports methods:
-
-NS_IMPL_ADDREF(nsSVGPathSegList)
-NS_IMPL_RELEASE(nsSVGPathSegList)
-
-DOMCI_DATA(SVGPathSegList, nsSVGPathSegList)
-
-NS_INTERFACE_MAP_BEGIN(nsSVGPathSegList)
-  NS_INTERFACE_MAP_ENTRY(nsISVGValue)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMSVGPathSegList)
-  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
-  NS_INTERFACE_MAP_ENTRY(nsISVGValueObserver)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGPathSegList)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISVGValue)
-NS_INTERFACE_MAP_END
-
-//----------------------------------------------------------------------
-// nsISVGValue methods:
-
-NS_IMETHODIMP
-nsSVGPathSegList::SetValueString(const nsAString& aValue)
-{
-  WillModify();
-  ReleaseSegments(PR_FALSE);
-  nsSVGPathDataParserToDOM parser(&mSegments);
-  nsresult rv = parser.Parse(aValue);
-
-  PRInt32 count = mSegments.Count();
-  for (PRInt32 i=0; i<count; ++i) {
-    nsSVGPathSeg* seg = static_cast<nsSVGPathSeg*>(mSegments.ObjectAt(i));
-    seg->SetCurrentList(this);
-  }
-
-  if (NS_FAILED(rv)) {
-    NS_ERROR("path data parse error!");
-    ReleaseSegments(PR_FALSE);
-  }
-  DidModify();
-  return rv;
-}
-
-NS_IMETHODIMP
-nsSVGPathSegList::GetValueString(nsAString& aValue)
-{
-  aValue.Truncate();
-
-  PRInt32 count = mSegments.Count();
-
-  if (count<=0) return NS_OK;
-
-  PRInt32 i = 0;
-
-  while (1) {
-    nsSVGPathSeg* seg = static_cast<nsSVGPathSeg*>(mSegments.ObjectAt(i));
-
-    nsAutoString str;
-    seg->GetValueString(str);
-    aValue.Append(str);
-
-    if (++i >= count) break;
-
-    aValue.AppendLiteral(" ");
-  }
-
-  return NS_OK;
-}
-
-//----------------------------------------------------------------------
-// nsIDOMSVGPathSegList methods:
-
-/* readonly attribute unsigned long numberOfItems; */
-NS_IMETHODIMP nsSVGPathSegList::GetNumberOfItems(PRUint32 *aNumberOfItems)
-{
-  *aNumberOfItems = mSegments.Count();
-  return NS_OK;
-}
-
-/* void clear (); */
-NS_IMETHODIMP nsSVGPathSegList::Clear()
-{
-  WillModify();
-  ReleaseSegments();
-  DidModify();
-  return NS_OK;
-}
-
-/* nsIDOMSVGPathSeg initialize (in nsIDOMSVGPathSeg newItem); */
-NS_IMETHODIMP nsSVGPathSegList::Initialize(nsIDOMSVGPathSeg *newItem,
-                                           nsIDOMSVGPathSeg **_retval)
-{
-  NS_ENSURE_NATIVE_PATH_SEG(newItem, _retval);
-  Clear();
-  return AppendItem(newItem, _retval);
-}
-
-/* nsIDOMSVGPathSeg getItem (in unsigned long index); */
-NS_IMETHODIMP nsSVGPathSegList::GetItem(PRUint32 index, nsIDOMSVGPathSeg **_retval)
-{
-  if (index >= static_cast<PRUint32>(mSegments.Count())) {
-    *_retval = nsnull;
-    return NS_ERROR_DOM_INDEX_SIZE_ERR;
-  }
-
-  *_retval  = mSegments.ObjectAt(index);
-  NS_ADDREF(*_retval);
-  return NS_OK;
-}
-
-/* nsIDOMSVGPathSeg insertItemBefore (in nsIDOMSVGPathSeg newItem, in unsigned long index); */
-NS_IMETHODIMP nsSVGPathSegList::InsertItemBefore(nsIDOMSVGPathSeg *newItem,
-                                                 PRUint32 index,
-                                                 nsIDOMSVGPathSeg **_retval)
-{
-  NS_ENSURE_NATIVE_PATH_SEG(newItem, _retval);
-
-  if (index >= static_cast<PRUint32>(mSegments.Count())) {
-    return NS_ERROR_DOM_INDEX_SIZE_ERR;
-  }
-
-  InsertElementAt(static_cast<nsSVGPathSeg*>(newItem), index);
-  NS_ADDREF(*_retval = newItem);
-
-  return NS_OK;
-}
-
-/* nsIDOMSVGPathSeg replaceItem (in nsIDOMSVGPathSeg newItem, in unsigned long index); */
-NS_IMETHODIMP nsSVGPathSegList::ReplaceItem(nsIDOMSVGPathSeg *newItem,
-                                            PRUint32 index,
-                                            nsIDOMSVGPathSeg **_retval)
-{
-  NS_ENSURE_NATIVE_PATH_SEG(newItem, _retval);
-
-  // immediately remove the new item from its current list
-  nsSVGPathSeg* newItemSeg = static_cast<nsSVGPathSeg*>(newItem);
-  RemoveFromCurrentList(newItemSeg);
-
-  if (index >= static_cast<PRUint32>(mSegments.Count())) {
-    return NS_ERROR_DOM_INDEX_SIZE_ERR;
-  }
-
-  // NOTE: the new item can never be the item we will be replacing now that we removed it from its current list beforehand
-  InsertElementAt(newItemSeg, index);
-  RemoveFromCurrentList(static_cast<nsSVGPathSeg*>(mSegments.ObjectAt(index+1)));
-  NS_ADDREF(*_retval = newItem);
-
-  return NS_OK;
-}
-
-/* nsIDOMSVGPathSeg removeItem (in unsigned long index); */
-NS_IMETHODIMP nsSVGPathSegList::RemoveItem(PRUint32 index, nsIDOMSVGPathSeg **_retval)
-{
-  if (index >= static_cast<PRUint32>(mSegments.Count())) {
-    *_retval = nsnull;
-    return NS_ERROR_DOM_INDEX_SIZE_ERR;
-  }
-
-  *_retval = mSegments.ObjectAt(index);
-  NS_ADDREF(*_retval);
-  WillModify();
-  RemoveElementAt(index);
-  DidModify();
-  return NS_OK;
-}
-
-/* nsIDOMSVGPathSeg appendItem (in nsIDOMSVGPathSeg newItem); */
-NS_IMETHODIMP nsSVGPathSegList::AppendItem(nsIDOMSVGPathSeg *newItem,
-                                           nsIDOMSVGPathSeg **_retval)
-{
-  NS_ENSURE_NATIVE_PATH_SEG(newItem, _retval);
-  NS_ADDREF(*_retval = newItem);
-  AppendElement(static_cast<nsSVGPathSeg*>(newItem));
-  return NS_OK;
-}
-
-
-//----------------------------------------------------------------------
-// nsISVGValueObserver methods
-
-NS_IMETHODIMP
-nsSVGPathSegList::WillModifySVGObservable(nsISVGValue* observable,
-                                          modificationType aModType)
-{
-  // This method is not yet used
-
-  NS_NOTYETIMPLEMENTED("nsSVGPathSegList::WillModifySVGObservable");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsSVGPathSegList::DidModifySVGObservable (nsISVGValue* observable,
-                                          modificationType aModType)
-{
-  // This method is not yet used
-
-  NS_NOTYETIMPLEMENTED("nsSVGPathSegList::DidModifySVGObservable");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-//----------------------------------------------------------------------
-// Implementation helpers
-
-void
-nsSVGPathSegList::ReleaseSegments(PRBool aModify)
-{
-  if (aModify) {
-    WillModify();
-  }
-  PRInt32 count = mSegments.Count();
-  for (PRInt32 i = 0; i < count; ++i) {
-    nsSVGPathSeg* seg = static_cast<nsSVGPathSeg*>(mSegments.ObjectAt(i));
-    seg->SetCurrentList(nsnull);
-  }
-  mSegments.Clear();
-  if (aModify) {
-    DidModify();
-  }
-}
-
-void
-nsSVGPathSegList::AppendElement(nsSVGPathSeg* aElement)
-{
-  WillModify();
-  // XXX: we should only remove an item from its current list if we
-  // successfully added it to this list
-  RemoveFromCurrentList(aElement);
-  mSegments.AppendObject(aElement);
-  aElement->SetCurrentList(this);
-  DidModify();
-}
-
-void
-nsSVGPathSegList::RemoveElementAt(PRInt32 index)
-{
-  WillModify();
-  nsSVGPathSeg* seg = static_cast<nsSVGPathSeg*>