Bug 816778 Part 3: Convert SVGTransform to WebIDL r=bz
authorDavid Zbarsky <dzbarsky@gmail.com>
Sat, 22 Dec 2012 23:54:20 -0500
changeset 126018 0ca634658b96fd7da279869443029e9144f22f16
parent 126017 9b19cd969afcaab7b9e4fde83480e37db7c20f83
child 126019 db3de623feca7b822530818767c4fe255ded7852
push id2151
push userlsblakk@mozilla.com
push dateTue, 19 Feb 2013 18:06:57 +0000
treeherdermozilla-beta@4952e88741ec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs816778
milestone20.0a1
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 816778 Part 3: Convert SVGTransform to WebIDL r=bz
content/svg/content/src/DOMSVGMatrix.h
content/svg/content/src/DOMSVGPointList.cpp
content/svg/content/src/DOMSVGTransform.cpp
content/svg/content/src/DOMSVGTransform.h
content/svg/content/src/DOMSVGTransformList.cpp
content/svg/content/src/DOMSVGTransformList.h
dom/bindings/Bindings.conf
dom/webidl/SVGTransform.webidl
dom/webidl/SVGTransformList.webidl
dom/webidl/WebIDL.mk
--- a/content/svg/content/src/DOMSVGMatrix.h
+++ b/content/svg/content/src/DOMSVGMatrix.h
@@ -89,17 +89,17 @@ public:
 
   ~DOMSVGMatrix() {
     if (mTransform) {
       mTransform->ClearMatrixTearoff(this);
     }
   }
 
   const gfxMatrix& Matrix() const {
-    return mTransform ? mTransform->Matrix() : mMatrix;
+    return mTransform ? mTransform->Matrixgfx() : mMatrix;
   }
 
   // WebIDL
   DOMSVGTransform* GetParentObject() const;
   virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope, bool* aTriedToWrap);
 
   float A() const { return static_cast<float>(Matrix().xx); }
   void SetA(float aA, ErrorResult& rv);
--- a/content/svg/content/src/DOMSVGPointList.cpp
+++ b/content/svg/content/src/DOMSVGPointList.cpp
@@ -432,17 +432,17 @@ DOMSVGPointList::RemoveItem(uint32_t aIn
   MaybeRemoveItemFromAnimValListAt(aIndex);
 
   // We have to return the removed item, so make sure it exists:
   EnsureItemAt(aIndex);
 
   // Notify the DOM item of removal *before* modifying the lists so that the
   // DOM item can copy its *old* value:
   mItems[aIndex]->RemovingFromList();
-  nsCOMPtr<DOMSVGPoint> result = mItems[aIndex];
+  nsRefPtr<DOMSVGPoint> result = mItems[aIndex];
 
   InternalList().RemoveItem(aIndex);
   mItems.RemoveElementAt(aIndex);
 
   UpdateListIndicesFromIndex(mItems, aIndex);
 
   Element()->DidChangePointList(emptyOrOldValue);
   if (AttrIsAnimating()) {
--- a/content/svg/content/src/DOMSVGTransform.cpp
+++ b/content/svg/content/src/DOMSVGTransform.cpp
@@ -6,16 +6,17 @@
 
 #include "DOMSVGTransform.h"
 #include "DOMSVGMatrix.h"
 #include "SVGAnimatedTransformList.h"
 #include "nsError.h"
 #include <math.h>
 #include "nsContentUtils.h"
 #include "nsAttrValueInlines.h"
+#include "mozilla/dom/SVGTransformBinding.h"
 
 namespace mozilla {
 
 //----------------------------------------------------------------------
 // nsISupports methods:
 
 // 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
@@ -23,241 +24,323 @@ namespace mozilla {
 // NS_SVG_VAL_IMPL_CYCLE_COLLECTION does.)
 NS_IMPL_CYCLE_COLLECTION_CLASS(DOMSVGTransform)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMSVGTransform)
   // We may not belong to a list, so we must null check tmp->mList.
   if (tmp->mList) {
     tmp->mList->mItems[tmp->mListIndex] = nullptr;
   }
 NS_IMPL_CYCLE_COLLECTION_UNLINK(mList)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMSVGTransform)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mList)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMSVGTransform)
+NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
 NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMSVGTransform)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMSVGTransform)
 
 } // namespace mozilla
 DOMCI_DATA(SVGTransform, mozilla::DOMSVGTransform)
 namespace mozilla {
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGTransform)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(mozilla::DOMSVGTransform)
   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGTransform)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMSVGTransform)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGTransform)
 NS_INTERFACE_MAP_END
 
 
+JSObject*
+DOMSVGTransform::WrapObject(JSContext* aCx, JSObject* aScope, bool* aTriedToWrap)
+{
+  return mozilla::dom::SVGTransformBinding::Wrap(aCx, aScope, this, aTriedToWrap);
+}
+
 //----------------------------------------------------------------------
 // Ctors:
 
 DOMSVGTransform::DOMSVGTransform(DOMSVGTransformList *aList,
                                  uint32_t aListIndex,
                                  bool aIsAnimValItem)
   : mList(aList)
   , mListIndex(aListIndex)
   , mIsAnimValItem(aIsAnimValItem)
   , mTransform(nullptr)
   , mMatrixTearoff(nullptr)
 {
+  SetIsDOMBinding();
   // These shifts are in sync with the members in the header.
   NS_ABORT_IF_FALSE(aList &&
                     aListIndex <= MaxListIndex(), "bad arg");
 
   NS_ABORT_IF_FALSE(IndexIsValid(), "Bad index for DOMSVGNumber!");
 }
 
 DOMSVGTransform::DOMSVGTransform()
   : mList(nullptr)
   , mListIndex(0)
   , mIsAnimValItem(false)
   , mTransform(new SVGTransform()) // Default ctor for objects not in a list
                                    // initialises to matrix type with identity
                                    // matrix
   , mMatrixTearoff(nullptr)
 {
+  SetIsDOMBinding();
 }
 
 DOMSVGTransform::DOMSVGTransform(const gfxMatrix &aMatrix)
   : mList(nullptr)
   , mListIndex(0)
   , mIsAnimValItem(false)
   , mTransform(new SVGTransform(aMatrix))
   , mMatrixTearoff(nullptr)
 {
+  SetIsDOMBinding();
 }
 
 DOMSVGTransform::DOMSVGTransform(const SVGTransform &aTransform)
   : mList(nullptr)
   , mListIndex(0)
   , mIsAnimValItem(false)
   , mTransform(new SVGTransform(aTransform))
   , mMatrixTearoff(nullptr)
 {
+  SetIsDOMBinding();
 }
 
 
 //----------------------------------------------------------------------
 // nsIDOMSVGTransform methods:
 
 /* readonly attribute unsigned short type; */
+uint16_t
+DOMSVGTransform::Type() const
+{
+  return Transform().Type();
+}
+
 NS_IMETHODIMP
 DOMSVGTransform::GetType(uint16_t *aType)
 {
-  *aType = Transform().Type();
+  *aType = Type();
   return NS_OK;
 }
 
+already_AddRefed<DOMSVGMatrix>
+DOMSVGTransform::Matrix()
+{
+  if (!mMatrixTearoff) {
+    mMatrixTearoff = new DOMSVGMatrix(*this);
+  }
+  nsRefPtr<DOMSVGMatrix> matrix = mMatrixTearoff;
+  return matrix.forget();
+}
+
 /* readonly attribute nsIDOMSVGMatrix matrix; */
 NS_IMETHODIMP
 DOMSVGTransform::GetMatrix(nsIDOMSVGMatrix * *aMatrix)
 {
-  if (!mMatrixTearoff) {
-    mMatrixTearoff = new DOMSVGMatrix(*this);
-  }
-
-  NS_ADDREF(*aMatrix = mMatrixTearoff);
+  *aMatrix = Matrix().get();
   return NS_OK;
 }
 
 /* readonly attribute float angle; */
+float
+DOMSVGTransform::Angle() const
+{
+  return Transform().Angle();
+}
+
 NS_IMETHODIMP
 DOMSVGTransform::GetAngle(float *aAngle)
 {
-  *aAngle = Transform().Angle();
+  *aAngle = Angle();
   return NS_OK;
 }
 
+void
+DOMSVGTransform::SetMatrix(DOMSVGMatrix& aMatrix, ErrorResult& rv)
+{
+  if (mIsAnimValItem) {
+    rv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
+    return;
+  }
+  SetMatrix(aMatrix.Matrix());
+}
+
 /* void setMatrix (in nsIDOMSVGMatrix matrix); */
 NS_IMETHODIMP
 DOMSVGTransform::SetMatrix(nsIDOMSVGMatrix *matrix)
 {
-  if (mIsAnimValItem)
-    return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
-
   nsCOMPtr<DOMSVGMatrix> domMatrix = do_QueryInterface(matrix);
   if (!domMatrix)
     return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
 
-  SetMatrix(domMatrix->Matrix());
-  return NS_OK;
+  ErrorResult rv;
+  SetMatrix(*domMatrix, rv);
+  return rv.ErrorCode();
+}
+
+void
+DOMSVGTransform::SetTranslate(float tx, float ty, ErrorResult& rv)
+{
+  if (mIsAnimValItem) {
+    rv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
+    return;
+  }
+
+  if (Transform().Type() == nsIDOMSVGTransform::SVG_TRANSFORM_TRANSLATE &&
+      Matrixgfx().x0 == tx && Matrixgfx().y0 == ty) {
+    return;
+  }
+
+  nsAttrValue emptyOrOldValue = NotifyElementWillChange();
+  Transform().SetTranslate(tx, ty);
+  NotifyElementDidChange(emptyOrOldValue);
 }
 
 /* void setTranslate (in float tx, in float ty); */
 NS_IMETHODIMP
 DOMSVGTransform::SetTranslate(float tx, float ty)
 {
+  NS_ENSURE_FINITE2(tx, ty, NS_ERROR_ILLEGAL_VALUE);
+  ErrorResult rv;
+  SetTranslate(tx, ty, rv);
+  return rv.ErrorCode();
+}
+
+void
+DOMSVGTransform::SetScale(float sx, float sy, ErrorResult& rv)
+{
   if (mIsAnimValItem) {
-    return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
-  }
-  NS_ENSURE_FINITE2(tx, ty, NS_ERROR_ILLEGAL_VALUE);
-
-  if (Transform().Type() == nsIDOMSVGTransform::SVG_TRANSFORM_TRANSLATE &&
-      Matrix().x0 == tx && Matrix().y0 == ty) {
-    return NS_OK;
+    rv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
+    return;
   }
 
+  if (Transform().Type() == nsIDOMSVGTransform::SVG_TRANSFORM_SCALE &&
+      Matrixgfx().xx == sx && Matrixgfx().yy == sy) {
+    return;
+  }
   nsAttrValue emptyOrOldValue = NotifyElementWillChange();
-  Transform().SetTranslate(tx, ty);
+  Transform().SetScale(sx, sy);
   NotifyElementDidChange(emptyOrOldValue);
-
-  return NS_OK;
 }
 
 /* void setScale (in float sx, in float sy); */
 NS_IMETHODIMP
 DOMSVGTransform::SetScale(float sx, float sy)
 {
-  if (mIsAnimValItem) {
-    return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
-  }
   NS_ENSURE_FINITE2(sx, sy, NS_ERROR_ILLEGAL_VALUE);
-
-  if (Transform().Type() == nsIDOMSVGTransform::SVG_TRANSFORM_SCALE &&
-      Matrix().xx == sx && Matrix().yy == sy) {
-    return NS_OK;
-  }
-
-  nsAttrValue emptyOrOldValue = NotifyElementWillChange();
-  Transform().SetScale(sx, sy);
-  NotifyElementDidChange(emptyOrOldValue);
-
-  return NS_OK;
+  ErrorResult rv;
+  SetScale(sx, sy, rv);
+  return rv.ErrorCode();
 }
 
-/* void setRotate (in float angle, in float cx, in float cy); */
-NS_IMETHODIMP
-DOMSVGTransform::SetRotate(float angle, float cx, float cy)
+void
+DOMSVGTransform::SetRotate(float angle, float cx, float cy, ErrorResult& rv)
 {
   if (mIsAnimValItem) {
-    return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
+    rv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
+    return;
   }
-  NS_ENSURE_FINITE3(angle, cx, cy, NS_ERROR_ILLEGAL_VALUE);
 
   if (Transform().Type() == nsIDOMSVGTransform::SVG_TRANSFORM_ROTATE) {
     float currentCx, currentCy;
     Transform().GetRotationOrigin(currentCx, currentCy);
     if (Transform().Angle() == angle && currentCx == cx && currentCy == cy) {
-      return NS_OK;
+      return;
     }
   }
 
   nsAttrValue emptyOrOldValue = NotifyElementWillChange();
   Transform().SetRotate(angle, cx, cy);
   NotifyElementDidChange(emptyOrOldValue);
+}
 
-  return NS_OK;
+/* void setRotate (in float angle, in float cx, in float cy); */
+NS_IMETHODIMP
+DOMSVGTransform::SetRotate(float angle, float cx, float cy)
+{
+  NS_ENSURE_FINITE3(angle, cx, cy, NS_ERROR_ILLEGAL_VALUE);
+  ErrorResult rv;
+  SetRotate(angle, cx, cy, rv);
+  return rv.ErrorCode();
+}
+
+void
+DOMSVGTransform::SetSkewX(float angle, ErrorResult& rv)
+{
+  if (mIsAnimValItem) {
+    rv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
+    return;
+  }
+
+  if (Transform().Type() == nsIDOMSVGTransform::SVG_TRANSFORM_SKEWX &&
+      Transform().Angle() == angle) {
+    return;
+  }
+
+  nsAttrValue emptyOrOldValue = NotifyElementWillChange();
+  nsresult result = Transform().SetSkewX(angle);
+  if (NS_FAILED(result)) {
+    rv.Throw(result);
+    return;
+  }
+  NotifyElementDidChange(emptyOrOldValue);
 }
 
 /* void setSkewX (in float angle); */
 NS_IMETHODIMP
 DOMSVGTransform::SetSkewX(float angle)
 {
+  NS_ENSURE_FINITE(angle, NS_ERROR_ILLEGAL_VALUE);
+  ErrorResult rv;
+  SetSkewX(angle, rv);
+  return rv.ErrorCode();
+}
+
+void
+DOMSVGTransform::SetSkewY(float angle, ErrorResult& rv)
+{
   if (mIsAnimValItem) {
-    return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
+    rv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
+    return;
   }
-  NS_ENSURE_FINITE(angle, NS_ERROR_ILLEGAL_VALUE);
 
-  if (Transform().Type() == nsIDOMSVGTransform::SVG_TRANSFORM_SKEWX &&
+  if (Transform().Type() == nsIDOMSVGTransform::SVG_TRANSFORM_SKEWY &&
       Transform().Angle() == angle) {
-    return NS_OK;
+    return;
   }
 
   nsAttrValue emptyOrOldValue = NotifyElementWillChange();
-  nsresult rv = Transform().SetSkewX(angle);
-  if (NS_FAILED(rv))
-    return rv;
+  nsresult result = Transform().SetSkewY(angle);
+  if (NS_FAILED(result)) {
+    rv.Throw(result);
+    return;
+  }
   NotifyElementDidChange(emptyOrOldValue);
-
-  return NS_OK;
 }
 
 /* void setSkewY (in float angle); */
 NS_IMETHODIMP
 DOMSVGTransform::SetSkewY(float angle)
 {
-  if (mIsAnimValItem) {
-    return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
-  }
   NS_ENSURE_FINITE(angle, NS_ERROR_ILLEGAL_VALUE);
-
-  if (Transform().Type() == nsIDOMSVGTransform::SVG_TRANSFORM_SKEWY &&
-      Transform().Angle() == angle) {
-    return NS_OK;
-  }
-
-  nsAttrValue emptyOrOldValue = NotifyElementWillChange();
-  nsresult rv = Transform().SetSkewY(angle);
-  if (NS_FAILED(rv))
-    return rv;
-  NotifyElementDidChange(emptyOrOldValue);
-
-  return NS_OK;
+  ErrorResult rv;
+  SetSkewY(angle, rv);
+  return rv.ErrorCode();
 }
 
 
 //----------------------------------------------------------------------
 // List management methods:
 
 void
 DOMSVGTransform::InsertingIntoList(DOMSVGTransformList *aList,
@@ -318,17 +401,17 @@ DOMSVGTransform::IndexIsValid()
 
 void
 DOMSVGTransform::SetMatrix(const gfxMatrix& aMatrix)
 {
   NS_ABORT_IF_FALSE(!mIsAnimValItem,
       "Attempting to modify read-only transform");
 
   if (Transform().Type() == nsIDOMSVGTransform::SVG_TRANSFORM_MATRIX &&
-      SVGTransform::MatricesEqual(Matrix(), aMatrix)) {
+      SVGTransform::MatricesEqual(Matrixgfx(), aMatrix)) {
     return;
   }
 
   nsAttrValue emptyOrOldValue = NotifyElementWillChange();
   Transform().SetMatrix(aMatrix);
   NotifyElementDidChange(emptyOrOldValue);
 }
 
--- a/content/svg/content/src/DOMSVGTransform.h
+++ b/content/svg/content/src/DOMSVGTransform.h
@@ -10,16 +10,17 @@
 #include "DOMSVGTransformList.h"
 #include "nsAutoPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsDebug.h"
 #include "nsID.h"
 #include "nsIDOMSVGTransform.h"
 #include "nsTArray.h"
 #include "SVGTransform.h"
+#include "nsWrapperCache.h"
 #include "mozilla/Attributes.h"
 
 class nsSVGElement;
 
 struct gfxMatrix;
 
 // We make DOMSVGTransform a pseudo-interface to allow us to QI to it in order
 // to check that the objects that scripts pass in are our our *native* transform
@@ -34,45 +35,46 @@ struct gfxMatrix;
 
 namespace mozilla {
 
 class DOMSVGMatrix;
 
 /**
  * DOM wrapper for an SVG transform. See DOMSVGLength.h.
  */
-class DOMSVGTransform MOZ_FINAL : public nsIDOMSVGTransform
+class DOMSVGTransform MOZ_FINAL : public nsIDOMSVGTransform,
+                                  public nsWrapperCache
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(MOZILLA_DOMSVGTRANSFORM_IID)
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_CLASS(DOMSVGTransform)
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DOMSVGTransform)
   NS_DECL_NSIDOMSVGTRANSFORM
 
   /**
    * Generic ctor for DOMSVGTransform objects that are created for an attribute.
    */
   DOMSVGTransform(DOMSVGTransformList *aList,
                   uint32_t aListIndex,
                   bool aIsAnimValItem);
 
   /**
    * Ctors for creating the objects returned by:
    *   SVGSVGElement.createSVGTransform(),
    *   SVGSVGElement.createSVGTransformFromMatrix(in SVGMatrix matrix),
    *   SVGTransformList.createSVGTransformFromMatrix(in SVGMatrix matrix)
    * which do not initially belong to an attribute.
    */
-  DOMSVGTransform();
-  DOMSVGTransform(const gfxMatrix &aMatrix);
+  explicit DOMSVGTransform();
+  explicit DOMSVGTransform(const gfxMatrix &aMatrix);
 
   /**
    * Ctor for creating an unowned copy. Used with Clone().
    */
-  DOMSVGTransform(const SVGTransform &aMatrix);
+  explicit DOMSVGTransform(const SVGTransform &aMatrix);
 
   ~DOMSVGTransform() {
     // Our matrix tear-off pointer should be cleared before we are destroyed
     // (since matrix tear-offs keep an owning reference to their transform, and
     // clear the tear-off pointer themselves if unlinked).
     NS_ABORT_IF_FALSE(!mMatrixTearoff, "Matrix tear-off pointer not cleared."
         " Transform being destroyed before matrix?");
     // Our mList's weak ref to us must be nulled out when we die. If GC has
@@ -134,23 +136,36 @@ public:
    * "lose" its value on being removed.)
    */
   void RemovingFromList();
 
   SVGTransform ToSVGTransform() const {
     return Transform();
   }
 
+  // WebIDL
+  DOMSVGTransformList* GetParentObject() const { return mList; }
+  virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope, bool* aTriedToWrap);
+  uint16_t Type() const;
+  already_AddRefed<DOMSVGMatrix> Matrix();
+  float Angle() const;
+  void SetMatrix(mozilla::DOMSVGMatrix& matrix, ErrorResult& rv);
+  void SetTranslate(float tx, float ty, ErrorResult& rv);
+  void SetScale(float sx, float sy, ErrorResult& rv);
+  void SetRotate(float angle, float cx, float cy, ErrorResult& rv);
+  void SetSkewX(float angle, ErrorResult& rv);
+  void SetSkewY(float angle, ErrorResult& rv);
+
 protected:
   // Interface for DOMSVGMatrix's use
   friend class DOMSVGMatrix;
   const bool IsAnimVal() const {
     return mIsAnimValItem;
   }
-  const gfxMatrix& Matrix() const {
+  const gfxMatrix& Matrixgfx() const {
     return Transform().Matrix();
   }
   void SetMatrix(const gfxMatrix& aMatrix);
   void ClearMatrixTearoff(DOMSVGMatrix* aMatrix);
 
 private:
   nsSVGElement* Element() {
     return mList->Element();
--- a/content/svg/content/src/DOMSVGTransformList.cpp
+++ b/content/svg/content/src/DOMSVGTransformList.cpp
@@ -175,57 +175,58 @@ DOMSVGTransformList::Clear(ErrorResult& 
 NS_IMETHODIMP
 DOMSVGTransformList::Clear()
 {
   ErrorResult rv;
   Clear(rv);
   return rv.ErrorCode();
 }
 
-already_AddRefed<nsIDOMSVGTransform>
-DOMSVGTransformList::Initialize(nsIDOMSVGTransform *newItem, ErrorResult& error)
+already_AddRefed<DOMSVGTransform>
+DOMSVGTransformList::Initialize(DOMSVGTransform& newItem, ErrorResult& error)
 {
   if (IsAnimValList()) {
     error.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
     return nullptr;
   }
 
   // If newItem is already in a list we should insert a clone of newItem, and
   // for consistency, this should happen even if *this* is the list that
   // newItem is currently in. Note that in the case of newItem 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 newItem, it would actually insert newItem. To prevent that from
   // happening we have to do the clone here, if necessary.
 
-  nsCOMPtr<DOMSVGTransform> domItem = do_QueryInterface(newItem);
-  if (!domItem) {
-    error.Throw(NS_ERROR_DOM_SVG_WRONG_TYPE_ERR);
-    return nullptr;
-  }
+  nsCOMPtr<DOMSVGTransform> domItem = &newItem;
   if (domItem->HasOwner()) {
-    newItem = domItem->Clone();
+    domItem = newItem.Clone();
   }
 
   Clear(error);
   MOZ_ASSERT(!error.Failed(), "How could this fail?");
-  return InsertItemBefore(newItem, 0, error);
+  return InsertItemBefore(*domItem, 0, error);
 }
 
 /* nsIDOMSVGTransform initialize (in nsIDOMSVGTransform newItem); */
 NS_IMETHODIMP
 DOMSVGTransformList::Initialize(nsIDOMSVGTransform *newItem,
                                 nsIDOMSVGTransform **_retval)
 {
+  nsCOMPtr<DOMSVGTransform> domItem = do_QueryInterface(newItem);
+  if (!domItem) {
+    *_retval = nullptr;
+    return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
+  }
   ErrorResult rv;
-  *_retval = Initialize(newItem, rv).get();
+  *_retval = Initialize(*domItem, rv).get();
   return rv.ErrorCode();
 }
 
-nsIDOMSVGTransform*
+DOMSVGTransform*
 DOMSVGTransformList::IndexedGetter(uint32_t index, bool& found,
                                    ErrorResult& error)
 {
   if (IsAnimValList()) {
     Element()->FlushAnimations();
   }
   found = index < LengthNoFlush();
   if (found) {
@@ -239,38 +240,34 @@ DOMSVGTransformList::IndexedGetter(uint3
 NS_IMETHODIMP
 DOMSVGTransformList::GetItem(uint32_t index, nsIDOMSVGTransform **_retval)
 {
   ErrorResult rv;
   NS_IF_ADDREF(*_retval = GetItem(index, rv));
   return rv.ErrorCode();
 }
 
-already_AddRefed<nsIDOMSVGTransform>
-DOMSVGTransformList::InsertItemBefore(nsIDOMSVGTransform *newItem,
+already_AddRefed<DOMSVGTransform>
+DOMSVGTransformList::InsertItemBefore(DOMSVGTransform& newItem,
                                       uint32_t index, ErrorResult& error)
 {
   if (IsAnimValList()) {
     error.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
     return nullptr;
   }
 
   index = NS_MIN(index, LengthNoFlush());
   if (index >= DOMSVGTransform::MaxListIndex()) {
     error.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     return nullptr;
   }
 
-  nsCOMPtr<DOMSVGTransform> domItem = do_QueryInterface(newItem);
-  if (!domItem) {
-    error.Throw(NS_ERROR_DOM_SVG_WRONG_TYPE_ERR);
-    return nullptr;
-  }
-  if (domItem->HasOwner()) {
-    domItem = domItem->Clone(); // must do this before changing anything!
+  nsCOMPtr<DOMSVGTransform> domItem = &newItem;
+  if (newItem.HasOwner()) {
+    domItem = newItem.Clone(); // must do this before changing anything!
   }
 
   // Ensure we have enough memory so we can avoid complex error handling below:
   if (!mItems.SetCapacity(mItems.Length() + 1) ||
       !InternalList().SetCapacity(InternalList().Length() + 1)) {
     error.Throw(NS_ERROR_OUT_OF_MEMORY);
     return nullptr;
   }
@@ -298,41 +295,43 @@ DOMSVGTransformList::InsertItemBefore(ns
 
 /* nsIDOMSVGTransform insertItemBefore (in nsIDOMSVGTransform newItem,
  *                                      in unsigned long index); */
 NS_IMETHODIMP
 DOMSVGTransformList::InsertItemBefore(nsIDOMSVGTransform *newItem,
                                       uint32_t index,
                                       nsIDOMSVGTransform **_retval)
 {
+  nsCOMPtr<DOMSVGTransform> domItem = do_QueryInterface(newItem);
+  if (!domItem) {
+    *_retval = nullptr;
+    return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
+  }
   ErrorResult rv;
-  *_retval = InsertItemBefore(newItem, index, rv).get();
+  *_retval = InsertItemBefore(*domItem, index, rv).get();
   return rv.ErrorCode();
 }
 
-already_AddRefed<nsIDOMSVGTransform>
-DOMSVGTransformList::ReplaceItem(nsIDOMSVGTransform *newItem,
+already_AddRefed<DOMSVGTransform>
+DOMSVGTransformList::ReplaceItem(DOMSVGTransform& newItem,
                                  uint32_t index, ErrorResult& error)
 {
   if (IsAnimValList()) {
     error.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
     return nullptr;
   }
 
-  nsCOMPtr<DOMSVGTransform> domItem = do_QueryInterface(newItem);
-  if (!domItem) {
-    error.Throw(NS_ERROR_DOM_SVG_WRONG_TYPE_ERR);
-    return nullptr;
-  }
   if (index >= LengthNoFlush()) {
     error.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     return nullptr;
   }
-  if (domItem->HasOwner()) {
-    domItem = domItem->Clone(); // must do this before changing anything!
+
+  nsCOMPtr<DOMSVGTransform> domItem = &newItem;
+  if (newItem.HasOwner()) {
+    domItem = newItem.Clone(); // must do this before changing anything!
   }
 
   nsAttrValue emptyOrOldValue = Element()->WillChangeTransformList();
   if (mItems[index]) {
     // Notify any existing DOM item of removal *before* modifying the lists so
     // that the DOM item can copy the *old* value at its index:
     mItems[index]->RemovingFromList();
   }
@@ -353,22 +352,27 @@ DOMSVGTransformList::ReplaceItem(nsIDOMS
 
 /* nsIDOMSVGTransform replaceItem (in nsIDOMSVGTransform newItem,
  *                                 in unsigned long index); */
 NS_IMETHODIMP
 DOMSVGTransformList::ReplaceItem(nsIDOMSVGTransform *newItem,
                                  uint32_t index,
                                  nsIDOMSVGTransform **_retval)
 {
+  nsCOMPtr<DOMSVGTransform> domItem = do_QueryInterface(newItem);
+  if (!domItem) {
+    *_retval = nullptr;
+    return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
+  }
   ErrorResult rv;
-  *_retval = ReplaceItem(newItem, index, rv).get();
+  *_retval = ReplaceItem(*domItem, index, rv).get();
   return rv.ErrorCode();
 }
 
-already_AddRefed<nsIDOMSVGTransform>
+already_AddRefed<DOMSVGTransform>
 DOMSVGTransformList::RemoveItem(uint32_t index, ErrorResult& error)
 {
   if (IsAnimValList()) {
     error.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
     return nullptr;
   }
 
   if (index >= LengthNoFlush()) {
@@ -383,17 +387,17 @@ DOMSVGTransformList::RemoveItem(uint32_t
   MaybeRemoveItemFromAnimValListAt(index);
 
   // We have to return the removed item, so make sure it exists:
   EnsureItemAt(index);
 
   // Notify the DOM item of removal *before* modifying the lists so that the
   // DOM item can copy its *old* value:
   mItems[index]->RemovingFromList();
-  nsCOMPtr<nsIDOMSVGTransform> result = mItems[index];
+  nsCOMPtr<DOMSVGTransform> result = mItems[index];
 
   InternalList().RemoveItem(index);
   mItems.RemoveElementAt(index);
 
   UpdateListIndicesFromIndex(mItems, index);
 
   Element()->DidChangeTransformList(emptyOrOldValue);
   if (mAList->IsAnimating()) {
@@ -411,25 +415,30 @@ DOMSVGTransformList::RemoveItem(uint32_t
   return rv.ErrorCode();
 }
 
 /* nsIDOMSVGTransform appendItem (in nsIDOMSVGTransform newItem); */
 NS_IMETHODIMP
 DOMSVGTransformList::AppendItem(nsIDOMSVGTransform *newItem,
                                 nsIDOMSVGTransform **_retval)
 {
+  nsCOMPtr<DOMSVGTransform> domItem = do_QueryInterface(newItem);
+  if (!domItem) {
+    *_retval = nullptr;
+    return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
+  }
   ErrorResult rv;
-  *_retval = AppendItem(newItem, rv).get();
+  *_retval = AppendItem(*domItem, rv).get();
   return rv.ErrorCode();
 }
 
-already_AddRefed<nsIDOMSVGTransform>
+already_AddRefed<DOMSVGTransform>
 DOMSVGTransformList::CreateSVGTransformFromMatrix(DOMSVGMatrix& matrix)
 {
-  nsCOMPtr<nsIDOMSVGTransform> result = new DOMSVGTransform(matrix.Matrix());
+  nsCOMPtr<DOMSVGTransform> result = new DOMSVGTransform(matrix.Matrix());
   return result.forget();
 }
 
 /* nsIDOMSVGTransform createSVGTransformFromMatrix (in nsIDOMSVGMatrix matrix);
  */
 NS_IMETHODIMP
 DOMSVGTransformList::CreateSVGTransformFromMatrix(nsIDOMSVGMatrix *matrix,
                                                   nsIDOMSVGTransform **_retval)
@@ -438,42 +447,43 @@ DOMSVGTransformList::CreateSVGTransformF
   if (!domItem) {
     *_retval = nullptr;
     return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
   }
   *_retval = CreateSVGTransformFromMatrix(*domItem).get();
   return NS_OK;
 }
 
-already_AddRefed<nsIDOMSVGTransform>
+already_AddRefed<DOMSVGTransform>
 DOMSVGTransformList::Consolidate(ErrorResult& error)
 {
   if (IsAnimValList()) {
     error.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
     return nullptr;
   }
 
-  if (LengthNoFlush() == 0)
+  if (LengthNoFlush() == 0) {
     return nullptr;
+  }
 
   // Note that SVG 1.1 says, "The consolidation operation creates new
   // SVGTransform object as the first and only item in the list" hence, even if
   // LengthNoFlush() == 1 we can't return that one item (after making it a
   // matrix type). We must orphan the existing item and then make a new one.
 
   // First calculate our matrix
   gfxMatrix mx = InternalList().GetConsolidationMatrix();
 
   // Then orphan the existing items
   Clear(error);
   MOZ_ASSERT(!error.Failed(), "How could this fail?");
 
   // And append the new transform
   nsRefPtr<DOMSVGTransform> transform = new DOMSVGTransform(mx);
-  return InsertItemBefore(transform, LengthNoFlush(), error);
+  return InsertItemBefore(*transform, LengthNoFlush(), error);
 }
 
 /* nsIDOMSVGTransform consolidate (); */
 NS_IMETHODIMP
 DOMSVGTransformList::Consolidate(nsIDOMSVGTransform **_retval)
 {
   ErrorResult rv;
   *_retval = Consolidate(rv).get();
--- a/content/svg/content/src/DOMSVGTransformList.h
+++ b/content/svg/content/src/DOMSVGTransformList.h
@@ -91,44 +91,44 @@ public:
   uint32_t NumberOfItems() const
   {
     if (IsAnimValList()) {
       Element()->FlushAnimations();
     }
     return LengthNoFlush();
   }
   void Clear(ErrorResult& error);
-  already_AddRefed<nsIDOMSVGTransform> Initialize(nsIDOMSVGTransform *newItem,
-                                                  ErrorResult& error);
-  nsIDOMSVGTransform* GetItem(uint32_t index, ErrorResult& error)
+  already_AddRefed<DOMSVGTransform> Initialize(DOMSVGTransform& newItem,
+                                               ErrorResult& error);
+  DOMSVGTransform* GetItem(uint32_t index, ErrorResult& error)
   {
     bool found;
-    nsIDOMSVGTransform* item = IndexedGetter(index, found, error);
+    DOMSVGTransform* item = IndexedGetter(index, found, error);
     if (!found) {
       error.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     }
     return item;
   }
-  nsIDOMSVGTransform* IndexedGetter(uint32_t index, bool& found,
-                                    ErrorResult& error);
-  already_AddRefed<nsIDOMSVGTransform> InsertItemBefore(nsIDOMSVGTransform *newItem,
-                                                        uint32_t index,
-                                                        ErrorResult& error);
-  already_AddRefed<nsIDOMSVGTransform> ReplaceItem(nsIDOMSVGTransform *newItem,
-                                                   uint32_t index,
-                                                   ErrorResult& error);
-  already_AddRefed<nsIDOMSVGTransform> RemoveItem(uint32_t index,
-                                                  ErrorResult& error);
-  already_AddRefed<nsIDOMSVGTransform> AppendItem(nsIDOMSVGTransform *newItem,
-                                                  ErrorResult& error)
+  DOMSVGTransform* IndexedGetter(uint32_t index, bool& found,
+                                 ErrorResult& error);
+  already_AddRefed<DOMSVGTransform> InsertItemBefore(DOMSVGTransform& newItem,
+                                                     uint32_t index,
+                                                     ErrorResult& error);
+  already_AddRefed<DOMSVGTransform> ReplaceItem(DOMSVGTransform& newItem,
+                                                uint32_t index,
+                                                ErrorResult& error);
+  already_AddRefed<DOMSVGTransform> RemoveItem(uint32_t index,
+                                               ErrorResult& error);
+  already_AddRefed<DOMSVGTransform> AppendItem(DOMSVGTransform& newItem,
+                                               ErrorResult& error)
   {
     return InsertItemBefore(newItem, LengthNoFlush(), error);
   }
-  already_AddRefed<nsIDOMSVGTransform> CreateSVGTransformFromMatrix(DOMSVGMatrix& matrix);
-  already_AddRefed<nsIDOMSVGTransform> Consolidate(ErrorResult& error);
+  already_AddRefed<DOMSVGTransform> CreateSVGTransformFromMatrix(DOMSVGMatrix& matrix);
+  already_AddRefed<DOMSVGTransform> Consolidate(ErrorResult& error);
   uint32_t Length() const
   {
     return NumberOfItems();
   }
 
 private:
 
   nsSVGElement* Element() const {
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -470,16 +470,21 @@ DOMInterfaces = {
 },
 
 'SVGPointList': {
     'nativeType': 'mozilla::DOMSVGPointList',
     'headerFile': 'DOMSVGPointList.h',
     'resultNotAddRefed': [ 'getItem' ]
 },
 
+'SVGTransform': {
+    'nativeType': 'mozilla::DOMSVGTransform',
+    'headerFile': 'DOMSVGTransform.h'
+},
+
 'SVGTransformList': {
     'nativeType': 'mozilla::DOMSVGTransformList',
     'headerFile': 'DOMSVGTransformList.h',
     'resultNotAddRefed': [ 'getItem' ]
 },
 
 'TextDecoder': [
 {
@@ -864,17 +869,16 @@ addExternalIface('Principal', nativeType
                  headerFile='nsIPrincipal.h', notflattened=True)
 addExternalIface('ProcessingInstruction', nativeType='nsXMLProcessingInstruction')
 addExternalIface('Range', nativeType='nsRange')
 addExternalIface("Rect")
 addExternalIface('StyleSheetList')
 addExternalIface('SVGLength')
 addExternalIface('SVGNumber')
 addExternalIface('SVGPathSeg')
-addExternalIface('SVGTransform')
 addExternalIface('Text', nativeType='nsTextNode')
 addExternalIface('TextMetrics', headerFile='nsIDOMCanvasRenderingContext2D.h')
 addExternalIface('TreeWalker')
 addExternalIface('Touch', headerFile='nsIDOMTouchEvent.h')
 addExternalIface('TouchList', headerFile='nsIDOMTouchEvent.h')
 addExternalIface('URI', nativeType='nsIURI', headerFile='nsIURI.h',
                  notflattened=True)
 addExternalIface('UserDataHandler')
new file mode 100644
--- /dev/null
+++ b/dom/webidl/SVGTransform.webidl
@@ -0,0 +1,41 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * http://www.w3.org/TR/SVG2/
+ *
+ * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
+ * liability, trademark and document use rules apply.
+ */
+
+interface SVGTransform {
+
+  // Transform Types
+  const unsigned short SVG_TRANSFORM_UNKNOWN = 0;
+  const unsigned short SVG_TRANSFORM_MATRIX = 1;
+  const unsigned short SVG_TRANSFORM_TRANSLATE = 2;
+  const unsigned short SVG_TRANSFORM_SCALE = 3;
+  const unsigned short SVG_TRANSFORM_ROTATE = 4;
+  const unsigned short SVG_TRANSFORM_SKEWX = 5;
+  const unsigned short SVG_TRANSFORM_SKEWY = 6;
+
+  readonly attribute unsigned short type;
+  readonly attribute SVGMatrix matrix;
+  readonly attribute float angle;
+
+  [Throws]
+  void setMatrix(SVGMatrix matrix);
+  [Throws]
+  void setTranslate(float tx, float ty);
+  [Throws]
+  void setScale(float sx, float sy);
+  [Throws]
+  void setRotate(float angle, float cx, float cy);
+  [Throws]
+  void setSkewX(float angle);
+  [Throws]
+  void setSkewY(float angle);
+};
+
--- a/dom/webidl/SVGTransformList.webidl
+++ b/dom/webidl/SVGTransformList.webidl
@@ -5,18 +5,16 @@
  *
  * The origin of this IDL file is
  * http://www.w3.org/TR/SVG11/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
-interface SVGTransform;
-
 interface SVGTransformList {
   readonly attribute unsigned long numberOfItems;
   [Throws]
   void clear();
   [Throws]
   SVGTransform initialize(SVGTransform newItem);
   [Throws]
   getter SVGTransform getItem(unsigned long index);
@@ -25,13 +23,13 @@ interface SVGTransformList {
   [Throws]
   SVGTransform replaceItem(SVGTransform newItem, unsigned long index);
   [Throws]
   SVGTransform removeItem(unsigned long index);
   [Throws]
   SVGTransform appendItem(SVGTransform newItem);
   SVGTransform createSVGTransformFromMatrix(SVGMatrix matrix);
   [Throws]
-  SVGTransform consolidate();
+  SVGTransform? consolidate();
 
   // Mozilla-specific stuff
   readonly attribute unsigned long length; // synonym for numberOfItems
 };
--- a/dom/webidl/WebIDL.mk
+++ b/dom/webidl/WebIDL.mk
@@ -69,16 +69,17 @@ webidl_files = \
   RGBColor.webidl \
   Screen.webidl \
   SVGLengthList.webidl \
   SVGMatrix.webidl \
   SVGNumberList.webidl \
   SVGPathSegList.webidl \
   SVGPoint.webidl \
   SVGPointList.webidl \
+  SVGTransform.webidl \
   SVGTransformList.webidl \
   TextDecoder.webidl \
   TextEncoder.webidl \
   URL.webidl \
   WebSocket.webidl \
   XMLHttpRequest.webidl \
   XMLHttpRequestEventTarget.webidl \
   XMLHttpRequestUpload.webidl \