Bug 435356. Stop using nsIDOMSVGMatrix internally. r=longsonr
authorJonathan Watt <jwatt@jwatt.org>
Tue, 21 Jul 2009 22:34:37 +0200
changeset 30502 941a73f2fc2142c17d5e8f8bba13968eae523c2e
parent 30501 b1d9fe5a27e66e4004b92e4e5b212408e0eec1df
child 30503 4e8e7061db9e98e6381a0d0cb32f5921179396fe
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslongsonr
bugs435356
milestone1.9.2a1pre
Bug 435356. Stop using nsIDOMSVGMatrix internally. r=longsonr
content/svg/content/src/nsSVGElement.cpp
content/svg/content/src/nsSVGFilters.cpp
content/svg/content/src/nsSVGForeignObjectElement.cpp
content/svg/content/src/nsSVGForeignObjectElement.h
content/svg/content/src/nsSVGGraphicElement.cpp
content/svg/content/src/nsSVGGraphicElement.h
content/svg/content/src/nsSVGLength.cpp
content/svg/content/src/nsSVGMarkerElement.cpp
content/svg/content/src/nsSVGMarkerElement.h
content/svg/content/src/nsSVGPathElement.cpp
content/svg/content/src/nsSVGPathElement.h
content/svg/content/src/nsSVGPathGeometryElement.cpp
content/svg/content/src/nsSVGPathGeometryElement.h
content/svg/content/src/nsSVGPatternElement.cpp
content/svg/content/src/nsSVGSVGElement.cpp
content/svg/content/src/nsSVGSVGElement.h
layout/svg/base/src/nsISVGChildFrame.h
layout/svg/base/src/nsSVGClipPathFrame.cpp
layout/svg/base/src/nsSVGClipPathFrame.h
layout/svg/base/src/nsSVGContainerFrame.h
layout/svg/base/src/nsSVGFilterFrame.cpp
layout/svg/base/src/nsSVGFilterInstance.cpp
layout/svg/base/src/nsSVGFilterInstance.h
layout/svg/base/src/nsSVGGFrame.cpp
layout/svg/base/src/nsSVGImageFrame.cpp
layout/svg/base/src/nsSVGInnerSVGFrame.cpp
layout/svg/base/src/nsSVGIntegrationUtils.cpp
layout/svg/base/src/nsSVGIntegrationUtils.h
layout/svg/base/src/nsSVGMarkerFrame.cpp
layout/svg/base/src/nsSVGMaskFrame.cpp
layout/svg/base/src/nsSVGMaskFrame.h
layout/svg/base/src/nsSVGOuterSVGFrame.cpp
layout/svg/base/src/nsSVGPathGeometryFrame.cpp
layout/svg/base/src/nsSVGPathGeometryFrame.h
layout/svg/base/src/nsSVGPatternFrame.cpp
layout/svg/base/src/nsSVGPatternFrame.h
layout/svg/base/src/nsSVGTSpanFrame.cpp
layout/svg/base/src/nsSVGTextContainerFrame.cpp
layout/svg/base/src/nsSVGTextPathFrame.cpp
layout/svg/base/src/nsSVGUseFrame.cpp
layout/svg/base/src/nsSVGUtils.cpp
layout/svg/base/src/nsSVGUtils.h
--- a/content/svg/content/src/nsSVGElement.cpp
+++ b/content/svg/content/src/nsSVGElement.cpp
@@ -927,18 +927,18 @@ nsSVGElement::GetOwnerSVGElement(nsIDOMS
   // this situation can e.g. occur during content tree teardown. 
   return NS_ERROR_FAILURE;
 }
 
 /* readonly attribute nsIDOMSVGElement viewportElement; */
 NS_IMETHODIMP
 nsSVGElement::GetViewportElement(nsIDOMSVGElement * *aViewportElement)
 {
-  nsSVGUtils::GetNearestViewportElement(this, aViewportElement);
-  return NS_OK; // we can't throw exceptions from this API.
+  *aViewportElement = nsSVGUtils::GetNearestViewportElement(this).get();
+  return NS_OK;
 }
 
 //----------------------------------------------------------------------
 // nsISVGValueObserver methods:
 
 NS_IMETHODIMP
 nsSVGElement::WillModifySVGObservable(nsISVGValue* observable,
                                       nsISVGValue::modificationType aModType)
--- a/content/svg/content/src/nsSVGFilters.cpp
+++ b/content/svg/content/src/nsSVGFilters.cpp
@@ -52,24 +52,24 @@
 #include "nsISVGValueUtils.h"
 #include "nsSVGFilters.h"
 #include "nsLayoutUtils.h"
 #include "nsSVGUtils.h"
 #include "nsStyleContext.h"
 #include "nsIDocument.h"
 #include "nsIFrame.h"
 #include "gfxContext.h"
+#include "gfxMatrix.h"
 #include "nsSVGLengthList.h"
 #include "nsIDOMSVGURIReference.h"
 #include "nsImageLoadingContent.h"
 #include "imgIContainer.h"
 #include "nsNetUtil.h"
 #include "nsSVGPreserveAspectRatio.h"
 #include "nsIInterfaceRequestorUtils.h"
-#include "nsSVGMatrix.h"
 #include "nsSVGFilterElement.h"
 #include "nsSVGString.h"
 
 #if defined(XP_WIN) 
 // Prevent Windows redefining LoadImage
 #ifndef WINCE
 #undef LoadImage
 #endif
@@ -5387,27 +5387,29 @@ nsSVGFEImageElement::Filter(nsSVGFilterI
 
   if (thebesPattern) {
     thebesPattern->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(frame));
 
     PRInt32 nativeWidth, nativeHeight;
     imageContainer->GetWidth(&nativeWidth);
     imageContainer->GetHeight(&nativeHeight);
 
-    nsCOMPtr<nsIDOMSVGMatrix> trans;
     const gfxRect& filterSubregion = aTarget->mFilterPrimitiveSubregion;
-    trans = nsSVGUtils::GetViewBoxTransform(filterSubregion.Width(), filterSubregion.Height(),
-                                            0, 0, nativeWidth, nativeHeight,
-                                            mPreserveAspectRatio);
-    nsCOMPtr<nsIDOMSVGMatrix> xy, fini;
-    NS_NewSVGMatrix(getter_AddRefs(xy), 1, 0, 0, 1, filterSubregion.X(), filterSubregion.Y());
-    xy->Multiply(trans, getter_AddRefs(fini));
-
+
+    gfxMatrix viewBoxTM =
+      nsSVGUtils::GetViewBoxTransform(filterSubregion.Width(), filterSubregion.Height(),
+                                      0,0, nativeWidth, nativeHeight,
+                                      mPreserveAspectRatio);
+
+    gfxMatrix xyTM = gfxMatrix().Translate(gfxPoint(filterSubregion.X(), filterSubregion.Y()));
+
+    gfxMatrix TM = viewBoxTM * xyTM;
+    
     gfxContext ctx(aTarget->mImage);
-    nsSVGUtils::CompositePatternMatrix(&ctx, thebesPattern, fini, nativeWidth, nativeHeight, 1.0);
+    nsSVGUtils::CompositePatternMatrix(&ctx, thebesPattern, TM, nativeWidth, nativeHeight, 1.0);
   }
 
   return NS_OK;
 }
 
 nsIntRect
 nsSVGFEImageElement::ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
         const nsSVGFilterInstance& aInstance)
--- a/content/svg/content/src/nsSVGForeignObjectElement.cpp
+++ b/content/svg/content/src/nsSVGForeignObjectElement.cpp
@@ -112,35 +112,16 @@ nsSVGForeignObjectElement::PrependLocalT
   gfxMatrix matrix = nsSVGForeignObjectElementBase::PrependLocalTransformTo(aMatrix);
   
   // now translate by our 'x' and 'y':
   float x, y;
   GetAnimatedLengthValues(&x, &y, nsnull);
   return gfxMatrix().Translate(gfxPoint(x, y)) * matrix;
 }
 
-nsresult
-nsSVGForeignObjectElement::AppendTransform(nsIDOMSVGMatrix *aCTM,
-                                           nsIDOMSVGMatrix **_retval)
-{
-  nsresult rv;
-  // foreignObject is one of establishing-viewport elements.
-  // so we are translated by foreignObject's x and y attribs.
-  float x, y;
-  GetAnimatedLengthValues(&x, &y, nsnull);
-  nsCOMPtr<nsIDOMSVGMatrix> translate;
-  rv = NS_NewSVGMatrix(getter_AddRefs(translate), 1, 0, 0, 1, x, y);
-  if (NS_FAILED(rv)) return rv;
-  nsCOMPtr<nsIDOMSVGMatrix> tmp;
-  rv = aCTM->Multiply(translate, getter_AddRefs(tmp));
-  if (NS_FAILED(rv)) return rv;
-
-  return nsSVGGraphicElement::AppendTransform(tmp, _retval);
-}
-
 //----------------------------------------------------------------------
 // nsIContent methods
 
 NS_IMETHODIMP_(PRBool)
 nsSVGForeignObjectElement::IsAttributeMapped(const nsIAtom* name) const
 {
   static const MappedAttributeEntry* const map[] = {
     sFEFloodMap,
--- a/content/svg/content/src/nsSVGForeignObjectElement.h
+++ b/content/svg/content/src/nsSVGForeignObjectElement.h
@@ -69,19 +69,16 @@ public:
   // nsSVGElement specializations:
   virtual gfxMatrix PrependLocalTransformTo(const gfxMatrix &aMatrix);
 
   // nsIContent interface
   NS_IMETHOD_(PRBool) IsAttributeMapped(const nsIAtom* name) const;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
-  // public helpers
-  nsresult AppendTransform(nsIDOMSVGMatrix *aCTM,
-                           nsIDOMSVGMatrix **_retval);
 protected:
 
   virtual LengthAttributesInfo GetLengthInfo();
   
   enum { X, Y, WIDTH, HEIGHT };
   nsSVGLength2 mLengthAttributes[4];
   static LengthInfo sLengthInfo[4];
 };
--- a/content/svg/content/src/nsSVGGraphicElement.cpp
+++ b/content/svg/content/src/nsSVGGraphicElement.cpp
@@ -70,24 +70,25 @@ nsSVGGraphicElement::nsSVGGraphicElement
 }
 
 //----------------------------------------------------------------------
 // nsIDOMSVGLocatable methods
 
 /* readonly attribute nsIDOMSVGElement nearestViewportElement; */
 NS_IMETHODIMP nsSVGGraphicElement::GetNearestViewportElement(nsIDOMSVGElement * *aNearestViewportElement)
 {
-  nsSVGUtils::GetNearestViewportElement(this, aNearestViewportElement);
-  return NS_OK; // we can't throw exceptions from this API.
+  *aNearestViewportElement = nsSVGUtils::GetNearestViewportElement(this).get();
+  return NS_OK;
 }
 
 /* readonly attribute nsIDOMSVGElement farthestViewportElement; */
 NS_IMETHODIMP nsSVGGraphicElement::GetFarthestViewportElement(nsIDOMSVGElement * *aFarthestViewportElement)
 {
-  return nsSVGUtils::GetFarthestViewportElement(this, aFarthestViewportElement);
+  *aFarthestViewportElement = nsSVGUtils::GetFarthestViewportElement(this).get();
+  return NS_OK;
 }
 
 /* nsIDOMSVGRect getBBox (); */
 NS_IMETHODIMP nsSVGGraphicElement::GetBBox(nsIDOMSVGRect **_retval)
 {
   *_retval = nsnull;
 
   nsIFrame* frame = GetPrimaryFrame(Flush_Layout);
@@ -97,51 +98,30 @@ NS_IMETHODIMP nsSVGGraphicElement::GetBB
 
   nsISVGChildFrame* svgframe = do_QueryFrame(frame);
   if (svgframe) {
     return NS_NewSVGRect(_retval, nsSVGUtils::GetBBox(frame));
   }
   return NS_ERROR_FAILURE;
 }
 
-/* Helper for GetCTM and GetScreenCTM */
-nsresult
-nsSVGGraphicElement::AppendTransform(nsIDOMSVGMatrix *aCTM,
-                                     nsIDOMSVGMatrix **_retval)
-{
-  if (!mTransforms) {
-    *_retval = aCTM;
-    NS_ADDREF(*_retval);
-    return NS_OK;
-  }
-
-  // append our local transformations
-  nsCOMPtr<nsIDOMSVGTransformList> transforms;
-  mTransforms->GetAnimVal(getter_AddRefs(transforms));
-  NS_ENSURE_TRUE(transforms, NS_ERROR_FAILURE);
-  nsCOMPtr<nsIDOMSVGMatrix> matrix =
-    nsSVGTransformList::GetConsolidationMatrix(transforms);
-  if (!matrix) {
-    *_retval = aCTM;
-    NS_ADDREF(*_retval);
-    return NS_OK;
-  }
-  return aCTM->Multiply(matrix, _retval);  // addrefs, so we don't
-}
-
 /* nsIDOMSVGMatrix getCTM (); */
 NS_IMETHODIMP nsSVGGraphicElement::GetCTM(nsIDOMSVGMatrix * *aCTM)
 {
-  return nsSVGUtils::GetCTM(this, aCTM);
+  gfxMatrix m = nsSVGUtils::GetCTM(this, PR_FALSE);
+  *aCTM = m.IsSingular() ? nsnull : NS_NewSVGMatrix(m).get();
+  return NS_OK;
 }
 
 /* nsIDOMSVGMatrix getScreenCTM (); */
 NS_IMETHODIMP nsSVGGraphicElement::GetScreenCTM(nsIDOMSVGMatrix * *aCTM)
 {
-  return nsSVGUtils::GetScreenCTM(this, aCTM);
+  gfxMatrix m = nsSVGUtils::GetCTM(this, PR_TRUE);
+  *aCTM = m.IsSingular() ? nsnull : NS_NewSVGMatrix(m).get();
+  return NS_OK;
 }
 
 /* nsIDOMSVGMatrix getTransformToElement (in nsIDOMSVGElement element); */
 NS_IMETHODIMP nsSVGGraphicElement::GetTransformToElement(nsIDOMSVGElement *element, nsIDOMSVGMatrix **_retval)
 {
   if (!element)
     return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
 
--- a/content/svg/content/src/nsSVGGraphicElement.h
+++ b/content/svg/content/src/nsSVGGraphicElement.h
@@ -59,19 +59,16 @@ public:
   NS_DECL_NSIDOMSVGLOCATABLE
   NS_DECL_NSIDOMSVGTRANSFORMABLE
 
   // nsIContent interface
   NS_IMETHOD_(PRBool) IsAttributeMapped(const nsIAtom* aAttribute) const;
 
   virtual gfxMatrix PrependLocalTransformTo(const gfxMatrix &aMatrix);
 
-  // public helpers
-  virtual nsresult AppendTransform(nsIDOMSVGMatrix *aCTM,
-                                   nsIDOMSVGMatrix **_retval);
 protected:
   // nsSVGElement overrides
   virtual PRBool IsEventName(nsIAtom* aName);
   
   virtual nsresult BeforeSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
                                  const nsAString* aValue, PRBool aNotify);
 
   nsCOMPtr<nsIDOMSVGAnimatedTransformList> mTransforms;
--- a/content/svg/content/src/nsSVGLength.cpp
+++ b/content/svg/content/src/nsSVGLength.cpp
@@ -33,17 +33,16 @@
  * 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 "nsSVGLength.h"
-#include "nsIDOMSVGMatrix.h"
 #include "nsGkAtoms.h"
 #include "nsSVGValue.h"
 #include "nsTextFormatter.h"
 #include "prdtoa.h"
 #include "nsCRT.h"
 #include "nsSVGSVGElement.h"
 #include "nsIDOMSVGNumber.h"
 #include "nsISVGValueUtils.h"
--- a/content/svg/content/src/nsSVGMarkerElement.cpp
+++ b/content/svg/content/src/nsSVGMarkerElement.cpp
@@ -37,16 +37,17 @@
 #include "nsGkAtoms.h"
 #include "nsCOMPtr.h"
 #include "nsISVGValueUtils.h"
 #include "nsSVGPreserveAspectRatio.h"
 #include "nsSVGMatrix.h"
 #include "nsDOMError.h"
 #include "nsSVGUtils.h"
 #include "nsSVGMarkerElement.h"
+#include "gfxMatrix.h"
 
 nsSVGElement::LengthInfo nsSVGMarkerElement::sLengthInfo[4] =
 {
   { &nsGkAtoms::refX, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, nsSVGUtils::X },
   { &nsGkAtoms::refY, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, nsSVGUtils::Y },
   { &nsGkAtoms::markerWidth, 3, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, nsSVGUtils::X },
   { &nsGkAtoms::markerHeight, 3, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, nsSVGUtils::Y },
 };
@@ -371,76 +372,62 @@ nsSVGPreserveAspectRatio *
 nsSVGMarkerElement::GetPreserveAspectRatio()
 {
   return &mPreserveAspectRatio;
 }
 
 //----------------------------------------------------------------------
 // public helpers
 
-nsresult
+gfxMatrix
 nsSVGMarkerElement::GetMarkerTransform(float aStrokeWidth,
-                                       float aX, float aY, float aAngle,
-                                       nsIDOMSVGMatrix **_retval)
+                                       float aX, float aY, float aAngle)
 {
   float scale = 1.0;
   if (mEnumAttributes[MARKERUNITS].GetAnimValue() ==
       SVG_MARKERUNITS_STROKEWIDTH)
     scale = aStrokeWidth;
 
   if (mOrientType.GetAnimValue() != SVG_MARKER_ORIENT_AUTO) {
     aAngle = mAngleAttributes[ORIENT].GetAnimValue();
   }
 
-  nsCOMPtr<nsIDOMSVGMatrix> matrix;
-  NS_NewSVGMatrix(getter_AddRefs(matrix),
-                  cos(aAngle) * scale,   sin(aAngle) * scale,
-                  -sin(aAngle) * scale,  cos(aAngle) * scale,
-                  aX,                    aY);
-    
-  *_retval = matrix;
-  NS_IF_ADDREF(*_retval);
-  return NS_OK;
+  return gfxMatrix(cos(aAngle) * scale,   sin(aAngle) * scale,
+                   -sin(aAngle) * scale,  cos(aAngle) * scale,
+                   aX,                    aY);
 }
 
-nsresult
-nsSVGMarkerElement::GetViewboxToViewportTransform(nsIDOMSVGMatrix **_retval)
+gfxMatrix
+nsSVGMarkerElement::GetViewBoxTransform()
 {
-  *_retval = nsnull;
-
   if (!mViewBoxToViewportTransform) {
     float viewportWidth =
       mLengthAttributes[MARKERWIDTH].GetAnimValue(mCoordCtx);
     float viewportHeight = 
       mLengthAttributes[MARKERHEIGHT].GetAnimValue(mCoordCtx);
    
     const nsSVGViewBoxRect& viewbox = mViewBox.GetAnimValue(); 
 
     if (viewbox.width <= 0.0f || viewbox.height <= 0.0f) {
-      return NS_ERROR_FAILURE; // invalid - don't paint element
+      return gfxMatrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); // invalid - don't paint element
     }
 
     float refX = mLengthAttributes[REFX].GetAnimValue(mCoordCtx);
     float refY = mLengthAttributes[REFY].GetAnimValue(mCoordCtx);
 
-    nsCOMPtr<nsIDOMSVGMatrix> vb2vp =
+    gfxMatrix viewBoxTM =
       nsSVGUtils::GetViewBoxTransform(viewportWidth, viewportHeight,
                                       viewbox.x, viewbox.y,
                                       viewbox.width, viewbox.height,
                                       mPreserveAspectRatio,
                                       PR_TRUE);
-    NS_ENSURE_TRUE(vb2vp, NS_ERROR_OUT_OF_MEMORY);
-    gfxPoint ref = nsSVGUtils::ConvertSVGMatrixToThebes(vb2vp).
-                    Transform(gfxPoint(refX, refY));
+
+    gfxPoint ref = viewBoxTM.Transform(gfxPoint(refX, refY));
 
-    nsCOMPtr<nsIDOMSVGMatrix> translate;
-    NS_NewSVGMatrix(getter_AddRefs(translate),
-                    1.0f, 0.0f, 0.0f, 1.0f, -ref.x, -ref.y);
-    NS_ENSURE_TRUE(translate, NS_ERROR_OUT_OF_MEMORY);
-    translate->Multiply(vb2vp, getter_AddRefs(mViewBoxToViewportTransform));
+    gfxMatrix TM = viewBoxTM * gfxMatrix().Translate(gfxPoint(-ref.x, -ref.y));
+
+    mViewBoxToViewportTransform = NS_NewSVGMatrix(TM);
   }
 
-  *_retval = mViewBoxToViewportTransform;
-  NS_IF_ADDREF(*_retval);
-  return NS_OK;
+  return nsSVGUtils::ConvertSVGMatrixToThebes(mViewBoxToViewportTransform);
 }
 
 
--- a/content/svg/content/src/nsSVGMarkerElement.h
+++ b/content/svg/content/src/nsSVGMarkerElement.h
@@ -126,20 +126,19 @@ public:
                              PRBool aNotify);
 
   // nsSVGElement specializations:
   virtual void DidChangeLength(PRUint8 aAttrEnum, PRBool aDoSetAttr);
   virtual void DidChangeViewBox(PRBool aDoSetAttr);
   virtual void DidChangePreserveAspectRatio(PRBool aDoSetAttr);
 
   // public helpers
-  nsresult GetMarkerTransform(float aStrokeWidth,
-                              float aX, float aY, float aAngle,
-                              nsIDOMSVGMatrix **_retval);
-  nsresult GetViewboxToViewportTransform(nsIDOMSVGMatrix **_retval);
+  gfxMatrix GetMarkerTransform(float aStrokeWidth,
+                               float aX, float aY, float aAngle);
+  gfxMatrix GetViewBoxTransform();
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
 protected:
 
   virtual PRBool ParseAttribute(PRInt32 aNameSpaceID, nsIAtom* aName,
                                 const nsAString& aValue,
                                 nsAttrValue& aResult);
--- a/content/svg/content/src/nsSVGPathElement.cpp
+++ b/content/svg/content/src/nsSVGPathElement.cpp
@@ -97,33 +97,33 @@ nsSVGPathElement::GetPathLength(nsIDOMSV
 }
 
 /* float getTotalLength (); */
 NS_IMETHODIMP
 nsSVGPathElement::GetTotalLength(float *_retval)
 {
   *_retval = 0;
 
-  nsRefPtr<gfxFlattenedPath> flat = GetFlattenedPath(nsnull);
+  nsRefPtr<gfxFlattenedPath> flat = GetFlattenedPath(gfxMatrix());
 
   if (!flat)
     return NS_ERROR_FAILURE;
 
   *_retval = flat->GetLength();
 
   return NS_OK;
 }
 
 /* nsIDOMSVGPoint getPointAtLength (in float distance); */
 NS_IMETHODIMP
 nsSVGPathElement::GetPointAtLength(float distance, nsIDOMSVGPoint **_retval)
 {
   NS_ENSURE_FINITE(distance, NS_ERROR_ILLEGAL_VALUE);
 
-  nsRefPtr<gfxFlattenedPath> flat = GetFlattenedPath(nsnull);
+  nsRefPtr<gfxFlattenedPath> flat = GetFlattenedPath(gfxMatrix());
   if (!flat)
     return NS_ERROR_FAILURE;
 
   float totalLength = flat->GetLength();
   if (HasAttr(kNameSpaceID_None, nsGkAtoms::pathLength)) {
     float pathLength = mPathLength.GetAnimValue();
     distance *= totalLength / pathLength;
   }
@@ -489,26 +489,22 @@ nsSVGPathElement::DidModifySVGObservable
 
     return rv;
   }
 
   return nsSVGPathElementBase::DidModifySVGObservable(observable, aModType);
 }
 
 already_AddRefed<gfxFlattenedPath>
-nsSVGPathElement::GetFlattenedPath(nsIDOMSVGMatrix *aMatrix)
+nsSVGPathElement::GetFlattenedPath(const gfxMatrix &aMatrix)
 {
   gfxContext ctx(nsSVGUtils::GetThebesComputationalSurface());
 
-  if (aMatrix) {
-    ctx.SetMatrix(nsSVGUtils::ConvertSVGMatrixToThebes(aMatrix));
-  }
-
+  ctx.SetMatrix(aMatrix);
   mPathData.Playback(&ctx);
-
   ctx.IdentityMatrix();
 
   return ctx.GetFlattenedPath();
 }
 
 //----------------------------------------------------------------------
 // nsSVGPathGeometryElement methods
 
--- a/content/svg/content/src/nsSVGPathElement.h
+++ b/content/svg/content/src/nsSVGPathElement.h
@@ -99,17 +99,17 @@ public:
                                      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(nsIDOMSVGMatrix *aMatrix);
+  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);
 
 protected:
 
--- a/content/svg/content/src/nsSVGPathGeometryElement.cpp
+++ b/content/svg/content/src/nsSVGPathGeometryElement.cpp
@@ -62,12 +62,12 @@ nsSVGPathGeometryElement::IsMarkable()
 }
 
 void
 nsSVGPathGeometryElement::GetMarkPoints(nsTArray<nsSVGMark> *aMarks)
 {
 }
 
 already_AddRefed<gfxFlattenedPath>
-nsSVGPathGeometryElement::GetFlattenedPath(nsIDOMSVGMatrix *aMatrix)
+nsSVGPathGeometryElement::GetFlattenedPath(const gfxMatrix &aMatrix)
 {
   return nsnull;
 }
--- a/content/svg/content/src/nsSVGPathGeometryElement.h
+++ b/content/svg/content/src/nsSVGPathGeometryElement.h
@@ -35,33 +35,33 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef __NS_SVGPATHGEOMETRYELEMENT_H__
 #define __NS_SVGPATHGEOMETRYELEMENT_H__
 
 #include "nsSVGGraphicElement.h"
 #include "nsTArray.h"
 #include "gfxPath.h"
+#include "gfxMatrix.h"
 
 struct nsSVGMark {
   float x, y, angle;
   nsSVGMark(float aX, float aY, float aAngle) :
     x(aX), y(aY), angle(aAngle) {}
 };
 
-class nsIDOMSVGMatrix;
 class gfxContext;
 
 typedef nsSVGGraphicElement nsSVGPathGeometryElementBase;
 
 class nsSVGPathGeometryElement : public nsSVGPathGeometryElementBase
 {
 public:
   nsSVGPathGeometryElement(nsINodeInfo *aNodeInfo);
 
   virtual PRBool AttributeDefinesGeometry(const nsIAtom *aName);
   virtual PRBool IsMarkable();
   virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks);
   virtual void ConstructPath(gfxContext *aCtx) = 0;
-  virtual already_AddRefed<gfxFlattenedPath> GetFlattenedPath(nsIDOMSVGMatrix *aMatrix);
+  virtual already_AddRefed<gfxFlattenedPath> GetFlattenedPath(const gfxMatrix &aMatrix);
 };
 
 #endif
--- a/content/svg/content/src/nsSVGPatternElement.cpp
+++ b/content/svg/content/src/nsSVGPatternElement.cpp
@@ -35,17 +35,16 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsSVGTransformList.h"
 #include "nsSVGAnimatedTransformList.h"
 #include "nsCOMPtr.h"
 #include "nsGkAtoms.h"
-#include "nsSVGMatrix.h"
 #include "nsSVGPatternElement.h"
 #include "nsIFrame.h"
 
 //--------------------- Patterns ------------------------
 
 nsSVGElement::LengthInfo nsSVGPatternElement::sLengthInfo[4] =
 {
   { &nsGkAtoms::x, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE, nsSVGUtils::X },
--- a/content/svg/content/src/nsSVGSVGElement.cpp
+++ b/content/svg/content/src/nsSVGSVGElement.cpp
@@ -741,25 +741,26 @@ nsSVGSVGElement::GetPreserveAspectRatio(
 
 //----------------------------------------------------------------------
 // nsIDOMSVGLocatable methods
 
 /* readonly attribute nsIDOMSVGElement nearestViewportElement; */
 NS_IMETHODIMP
 nsSVGSVGElement::GetNearestViewportElement(nsIDOMSVGElement * *aNearestViewportElement)
 {
-  nsSVGUtils::GetNearestViewportElement(this, aNearestViewportElement);
-  return NS_OK; // we can't throw exceptions from this API.
+  *aNearestViewportElement = nsSVGUtils::GetNearestViewportElement(this).get();
+  return NS_OK;
 }
 
 /* readonly attribute nsIDOMSVGElement farthestViewportElement; */
 NS_IMETHODIMP
 nsSVGSVGElement::GetFarthestViewportElement(nsIDOMSVGElement * *aFarthestViewportElement)
 {
-  return nsSVGUtils::GetFarthestViewportElement(this, aFarthestViewportElement);
+  *aFarthestViewportElement = nsSVGUtils::GetFarthestViewportElement(this).get();
+  return NS_OK;
 }
 
 /* nsIDOMSVGRect getBBox (); */
 NS_IMETHODIMP
 nsSVGSVGElement::GetBBox(nsIDOMSVGRect **_retval)
 {
   *_retval = nsnull;
 
@@ -770,78 +771,32 @@ nsSVGSVGElement::GetBBox(nsIDOMSVGRect *
 
   nsISVGChildFrame* svgframe = do_QueryFrame(frame);
   if (svgframe) {
     return NS_NewSVGRect(_retval, nsSVGUtils::GetBBox(frame));
   }
   return NS_ERROR_NOT_IMPLEMENTED; // XXX: outer svg
 }
 
-nsresult
-nsSVGSVGElement::AppendTransform(nsIDOMSVGMatrix *aCTM,
-                                 nsIDOMSVGMatrix **_retval)
-{
-  nsresult rv;
-
-  // first check what are our parents and calculate offsets accordingly.
-
-  float s=1, x=0, y=0;
-  nsIContent *ancestor = nsSVGUtils::GetParentElement(this);
-  if (ancestor && ancestor->GetNameSpaceID() == kNameSpaceID_SVG &&
-                  ancestor->Tag() == nsGkAtoms::foreignObject) {
-    // this is a nested <svg> element. immediate parent is an <foreignObject> element.
-    // we ignore this <svg> element's x and y attribs in layout so do the same.
-  } else {
-    nsCOMPtr<nsIDOMSVGElement> nearestViewportElement;
-    rv = nsSVGUtils::GetNearestViewportElement(this, getter_AddRefs(nearestViewportElement));
-    if (NS_FAILED(rv)) return rv;
-
-    if (!nearestViewportElement) {
-      if (IsRoot()) {
-        // we're the root element. get our currentScale and currentTranslate vals
-        s = mCurrentScale;
-        x = mCurrentTranslate.GetX();
-        y = mCurrentTranslate.GetY();
-      } else {
-        // we're inline in some non-SVG content. get our offset from the root
-        GetOffsetToAncestor(nsnull, x, y);
-      }
-    } else {
-      // this is a nested <svg> element.
-      GetAnimatedLengthValues(&x, &y, nsnull);
-    }
-  }
-
-  nsCOMPtr<nsIDOMSVGMatrix> local;
-  rv = NS_NewSVGMatrix(getter_AddRefs(local), s, 0, 0, s, x, y);
-  if (NS_FAILED(rv)) return rv;
-
-  // finally append our viewbox transform
-
-  nsCOMPtr<nsIDOMSVGMatrix> viewbox;
-  rv = GetViewboxToViewportTransform(getter_AddRefs(viewbox));
-  if (NS_FAILED(rv)) return rv;
-  nsCOMPtr<nsIDOMSVGMatrix> tmp;
-  rv = local->Multiply(viewbox, getter_AddRefs(tmp)); // addrefs, so we don't
-  if (NS_FAILED(rv)) return rv;
-  return aCTM->Multiply(tmp, _retval); // addrefs, so we don't
-}
-
 /* nsIDOMSVGMatrix getCTM (); */
 NS_IMETHODIMP
 nsSVGSVGElement::GetCTM(nsIDOMSVGMatrix * *aCTM)
 {
-  return nsSVGUtils::GetCTM(this, aCTM);
+  gfxMatrix m = nsSVGUtils::GetCTM(this, PR_FALSE);
+  *aCTM = m.IsSingular() ? nsnull : NS_NewSVGMatrix(m).get();
+  return NS_OK;
 }
 
 /* nsIDOMSVGMatrix getScreenCTM (); */
 NS_IMETHODIMP
 nsSVGSVGElement::GetScreenCTM(nsIDOMSVGMatrix **aCTM)
 {
-  return nsSVGUtils::GetScreenCTM(this, aCTM);
+  gfxMatrix m = nsSVGUtils::GetCTM(this, PR_TRUE);
+  *aCTM = m.IsSingular() ? nsnull : NS_NewSVGMatrix(m).get();
+  return NS_OK;
 }
 
 /* nsIDOMSVGMatrix getTransformToElement (in nsIDOMSVGElement element); */
 NS_IMETHODIMP
 nsSVGSVGElement::GetTransformToElement(nsIDOMSVGElement *element,
                                        nsIDOMSVGMatrix **_retval)
 {
   if (!element)
@@ -1022,53 +977,46 @@ nsSVGSVGElement::IsEventName(nsIAtom* aN
   */
   return nsContentUtils::IsEventAttributeName(aName,
          (EventNameType_SVGGraphic | EventNameType_SVGSVG));
 }
 
 //----------------------------------------------------------------------
 // public helpers:
 
-nsresult
-nsSVGSVGElement::GetViewboxToViewportTransform(nsIDOMSVGMatrix **_retval)
+gfxMatrix
+nsSVGSVGElement::GetViewBoxTransform()
 {
-  *_retval = nsnull;
-
   float viewportWidth, viewportHeight;
-  nsSVGSVGElement *ctx = GetCtx();
-  if (!ctx) {
-    // outer svg
+  if (nsSVGUtils::IsInnerSVG(this)) {
+    nsSVGSVGElement *ctx = GetCtx();
+    viewportWidth = mLengthAttributes[WIDTH].GetAnimValue(ctx);
+    viewportHeight = mLengthAttributes[HEIGHT].GetAnimValue(ctx);
+  } else {
     viewportWidth = mViewportWidth;
     viewportHeight = mViewportHeight;
-  } else {
-    viewportWidth = mLengthAttributes[WIDTH].GetAnimValue(ctx);
-    viewportHeight = mLengthAttributes[HEIGHT].GetAnimValue(ctx);
   }
 
-  nsSVGViewBoxRect viewbox;
+  nsSVGViewBoxRect viewBox;
   if (mViewBox.IsValid()) {
-    viewbox = mViewBox.GetAnimValue();
+    viewBox = mViewBox.GetAnimValue();
   } else {
-    viewbox.x = viewbox.y = 0.0f;
-    viewbox.width  = viewportWidth;
-    viewbox.height = viewportHeight;
+    viewBox.x = viewBox.y = 0.0f;
+    viewBox.width  = viewportWidth;
+    viewBox.height = viewportHeight;
   }
 
-  if (viewbox.width <= 0.0f || viewbox.height <= 0.0f) {
-    return NS_ERROR_FAILURE; // invalid - don't paint element
+  if (viewBox.width <= 0.0f || viewBox.height <= 0.0f) {
+    return gfxMatrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); // singular
   }
 
-  nsCOMPtr<nsIDOMSVGMatrix> xform =
-    nsSVGUtils::GetViewBoxTransform(viewportWidth, viewportHeight,
-                                    viewbox.x, viewbox.y,
-                                    viewbox.width, viewbox.height,
-                                    mPreserveAspectRatio);
-  xform.swap(*_retval);
-
-  return NS_OK;
+  return nsSVGUtils::GetViewBoxTransform(viewportWidth, viewportHeight,
+                                         viewBox.x, viewBox.y,
+                                         viewBox.width, viewBox.height,
+                                         mPreserveAspectRatio);
 }
 
 #ifdef MOZ_SMIL
 nsresult
 nsSVGSVGElement::BindToTree(nsIDocument* aDocument,
                             nsIContent* aParent,
                             nsIContent* aBindingParent,
                             PRBool aCompileEventHandlers)
@@ -1119,53 +1067,16 @@ nsSVGSVGElement::UnbindFromTree(PRBool a
 
   nsSVGSVGElementBase::UnbindFromTree(aDeep, aNullParent);
 }
 #endif // MOZ_SMIL
 
 //----------------------------------------------------------------------
 // implementation helpers
 
-// if an ancestor isn't specified, obtains offset from root frame
-void nsSVGSVGElement::GetOffsetToAncestor(nsIContent* ancestor,
-                                          float &x, float &y)
-{
-  x = 0.0f;
-  y = 0.0f;
-
-  nsIDocument *document = GetCurrentDoc();
-  if (!document) return;
-
-  // Flush all pending notifications so that our frames are uptodate
-  // Make sure to do this before we start grabbing layout objects like
-  // presshells.
-  document->FlushPendingNotifications(Flush_Layout);
-  
-  nsIPresShell *presShell = document->GetPrimaryShell();
-  if (!presShell) {
-    return;
-  }
-
-  nsPresContext *context = presShell->GetPresContext();
-  if (!context) {
-    return;
-  }
-
-  nsIFrame* frame = presShell->GetPrimaryFrameFor(this);
-  nsIFrame* ancestorFrame = ancestor ?
-                            presShell->GetPrimaryFrameFor(ancestor) :
-                            presShell->GetRootFrame();
-
-  if (frame && ancestorFrame) {
-    nsPoint point = frame->GetOffsetTo(ancestorFrame);
-    x = nsPresContext::AppUnitsToFloatCSSPixels(point.x);
-    y = nsPresContext::AppUnitsToFloatCSSPixels(point.y);
-  }
-}
-
 #ifdef MOZ_SMIL
 PRBool
 nsSVGSVGElement::WillBeOutermostSVG(nsIContent* aParent,
                                     nsIContent* aBindingParent) const
 {
   nsIContent* parent = aBindingParent ? aBindingParent : aParent;
 
   while (parent && parent->GetNameSpaceID() == kNameSpaceID_SVG) {
@@ -1256,29 +1167,31 @@ nsSVGSVGElement::GetMMPerPx(PRUint8 aCtx
 }
 
 //----------------------------------------------------------------------
 // nsSVGElement methods
 
 /* virtual */ gfxMatrix
 nsSVGSVGElement::PrependLocalTransformTo(const gfxMatrix &aMatrix)
 {
-  NS_ASSERTION(GetCtx(), "Should not be called on outer-<svg>");
-
-  float x, y;
-  GetAnimatedLengthValues(&x, &y, nsnull);
-  gfxMatrix matrix = aMatrix;
-  matrix.PreMultiply(gfxMatrix().Translate(gfxPoint(x, y)));
+  if (nsSVGUtils::IsInnerSVG(this)) {
+    float x, y;
+    GetAnimatedLengthValues(&x, &y, nsnull);
+    return GetViewBoxTransform() * gfxMatrix().Translate(gfxPoint(x, y)) * aMatrix;
+  }
 
-  nsCOMPtr<nsIDOMSVGMatrix> viewBoxTM;
-  nsresult res = GetViewboxToViewportTransform(getter_AddRefs(viewBoxTM));
-  if (NS_FAILED(res)) {
-    return gfxMatrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); // singular
+  if (IsRoot()) {
+    gfxMatrix zoomPanTM;
+    zoomPanTM.Translate(gfxPoint(mCurrentTranslate.GetX(), mCurrentTranslate.GetY()));
+    zoomPanTM.Scale(mCurrentScale, mCurrentScale);
+    return GetViewBoxTransform() * zoomPanTM * aMatrix;
   }
-  return matrix.PreMultiply(nsSVGUtils::ConvertSVGMatrixToThebes(viewBoxTM));
+
+  // outer-<svg>, but inline in some other content:
+  return GetViewBoxTransform() * aMatrix;
 }
 
 void
 nsSVGSVGElement::DidChangeLength(PRUint8 aAttrEnum, PRBool aDoSetAttr)
 {
   nsSVGSVGElementBase::DidChangeLength(aAttrEnum, aDoSetAttr);
 
   InvalidateTransformNotifyFrame();
--- a/content/svg/content/src/nsSVGSVGElement.h
+++ b/content/svg/content/src/nsSVGSVGElement.h
@@ -194,19 +194,17 @@ public:
   virtual void DidChangeViewBox(PRBool aDoSetAttr);
   virtual void DidChangePreserveAspectRatio(PRBool aDoSetAttr);
 
   // nsSVGSVGElement methods:
   float GetLength(PRUint8 mCtxType);
   float GetMMPerPx(PRUint8 mCtxType = 0);
 
   // public helpers:
-  nsresult GetViewboxToViewportTransform(nsIDOMSVGMatrix **_retval);
-  nsresult AppendTransform(nsIDOMSVGMatrix *aCTM,
-                           nsIDOMSVGMatrix **_retval);
+  gfxMatrix GetViewBoxTransform();
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
   svgFloatSize GetViewportSize() const {
     return svgFloatSize(mViewportWidth, mViewportHeight);
   }
 
   void SetViewportSize(const svgFloatSize& aSize) {
@@ -221,17 +219,16 @@ protected:
 #ifdef MOZ_SMIL
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               PRBool aCompileEventHandlers);
   virtual void UnbindFromTree(PRBool aDeep, PRBool aNullParent);
 #endif // MOZ_SMIL   
 
   // implementation helpers:
-  void GetOffsetToAncestor(nsIContent* ancestor, float &x, float &y);
 
   PRBool IsRoot() {
     NS_ASSERTION((IsInDoc() && !GetParent()) ==
                  (GetOwnerDoc() && (GetOwnerDoc()->GetRootContent() == this)),
                  "Can't determine if we're root");
     return IsInDoc() && !GetParent();
   }
 
--- a/layout/svg/base/src/nsISVGChildFrame.h
+++ b/layout/svg/base/src/nsISVGChildFrame.h
@@ -43,17 +43,16 @@
 #include "nsQueryFrame.h"
 #include "nsCOMPtr.h"
 #include "nsRect.h"
 #include "gfxRect.h"
 #include "gfxMatrix.h"
 
 class gfxContext;
 class nsPresContext;
-class nsIDOMSVGMatrix;
 class nsSVGRenderState;
 
 class nsISVGChildFrame : public nsQueryFrame
 {
 public:
   NS_DECLARE_FRAME_ACCESSOR(nsISVGChildFrame)
 
   // Paint this frame - aDirtyRect is the area being redrawn, in frame
--- a/layout/svg/base/src/nsSVGClipPathFrame.cpp
+++ b/layout/svg/base/src/nsSVGClipPathFrame.cpp
@@ -51,29 +51,29 @@ nsIFrame*
 NS_NewSVGClipPathFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsSVGClipPathFrame(aContext);
 }
 
 nsresult
 nsSVGClipPathFrame::ClipPaint(nsSVGRenderState* aContext,
                               nsIFrame* aParent,
-                              nsIDOMSVGMatrix *aMatrix)
+                              const gfxMatrix &aMatrix)
 {
   // If the flag is set when we get here, it means this clipPath frame
   // has already been used painting the current clip, and the document
   // has a clip reference loop.
   if (mInUse) {
     NS_WARNING("Clip loop detected!");
     return NS_OK;
   }
   AutoClipPathReferencer clipRef(this);
 
   mClipParent = aParent,
-  mClipParentMatrix = aMatrix;
+  mClipParentMatrix = NS_NewSVGMatrix(aMatrix);
 
   PRBool isTrivial = IsTrivial();
 
   nsAutoSVGRenderMode mode(aContext,
                            isTrivial ? nsSVGRenderState::CLIP
                                      : nsSVGRenderState::CLIP_MASK);
 
   for (nsIFrame* kid = mFrames.FirstChild(); kid;
@@ -92,30 +92,30 @@ nsSVGClipPathFrame::ClipPaint(nsSVGRende
     aContext->GetGfxContext()->NewPath();
   }
 
   return NS_OK;
 }
 
 PRBool
 nsSVGClipPathFrame::ClipHitTest(nsIFrame* aParent,
-                                nsIDOMSVGMatrix *aMatrix,
+                                const gfxMatrix &aMatrix,
                                 const nsPoint &aPoint)
 {
   // If the flag is set when we get here, it means this clipPath frame
   // has already been used in hit testing against the current clip,
   // and the document has a clip reference loop.
   if (mInUse) {
     NS_WARNING("Clip loop detected!");
     return PR_FALSE;
   }
   AutoClipPathReferencer clipRef(this);
 
   mClipParent = aParent,
-  mClipParentMatrix = aMatrix;
+  mClipParentMatrix = NS_NewSVGMatrix(aMatrix);
 
   for (nsIFrame* kid = mFrames.FirstChild(); kid;
        kid = kid->GetNextSibling()) {
     nsISVGChildFrame* SVGFrame = do_QueryFrame(kid);
     if (SVGFrame) {
       // Notify the child frame that we may be working with a
       // different transform, so it can update its covered region
       // (used to shortcut hit testing).
@@ -164,23 +164,17 @@ nsIAtom *
 nsSVGClipPathFrame::GetType() const
 {
   return nsGkAtoms::svgClipPathFrame;
 }
 
 gfxMatrix
 nsSVGClipPathFrame::GetCanvasTM()
 {
-  NS_ASSERTION(mClipParentMatrix, "null parent matrix");
-
   nsSVGClipPathElement *content = static_cast<nsSVGClipPathElement*>(mContent);
 
   gfxMatrix tm = content->PrependLocalTransformTo(
     nsSVGUtils::ConvertSVGMatrixToThebes(mClipParentMatrix));
 
-  nsCOMPtr<nsIDOMSVGMatrix> canvasTM = NS_NewSVGMatrix(tm);
-  nsCOMPtr<nsIDOMSVGMatrix> fini =
-         nsSVGUtils::AdjustMatrixForUnits(canvasTM,
+  return nsSVGUtils::AdjustMatrixForUnits(tm,
                                           &content->mEnumAttributes[nsSVGClipPathElement::CLIPPATHUNITS],
                                           mClipParent);
-
-  return nsSVGUtils::ConvertSVGMatrixToThebes(fini);
 }
--- a/layout/svg/base/src/nsSVGClipPathFrame.h
+++ b/layout/svg/base/src/nsSVGClipPathFrame.h
@@ -51,20 +51,20 @@ protected:
     nsSVGClipPathFrameBase(aContext),
     mClipParentMatrix(nsnull),
     mInUse(PR_FALSE) {}
 
 public:
   // nsSVGClipPathFrame methods:
   nsresult ClipPaint(nsSVGRenderState* aContext,
                      nsIFrame* aParent,
-                     nsIDOMSVGMatrix *aMatrix);
+                     const gfxMatrix &aMatrix);
 
   PRBool ClipHitTest(nsIFrame* aParent,
-                     nsIDOMSVGMatrix *aMatrix,
+                     const gfxMatrix &aMatrix,
                      const nsPoint &aPoint);
 
   // Check if this clipPath is made up of more than one geometry object.
   // If so, the clipping API in cairo isn't enough and we need to use
   // mask based clipping.
   PRBool IsTrivial();
 
 #ifdef DEBUG
--- a/layout/svg/base/src/nsSVGContainerFrame.h
+++ b/layout/svg/base/src/nsSVGContainerFrame.h
@@ -34,17 +34,16 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef NS_SVGCONTAINERFRAME_H
 #define NS_SVGCONTAINERFRAME_H
 
 #include "nsContainerFrame.h"
 #include "nsISVGChildFrame.h"
-#include "nsIDOMSVGMatrix.h"
 #include "nsSVGSVGElement.h"
 #include "gfxRect.h"
 #include "gfxMatrix.h"
 
 typedef nsContainerFrame nsSVGContainerFrameBase;
 
 class nsSVGContainerFrame : public nsSVGContainerFrameBase
 {
--- a/layout/svg/base/src/nsSVGFilterFrame.cpp
+++ b/layout/svg/base/src/nsSVGFilterFrame.cpp
@@ -31,17 +31,16 @@
  * 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 "nsSVGFilterFrame.h"
 #include "nsIDocument.h"
-#include "nsSVGMatrix.h"
 #include "nsSVGOuterSVGFrame.h"
 #include "nsGkAtoms.h"
 #include "nsSVGUtils.h"
 #include "nsSVGFilterElement.h"
 #include "nsSVGFilters.h"
 #include "gfxASurface.h"
 #include "gfxContext.h"
 #include "gfxImageSurface.h"
@@ -136,18 +135,17 @@ nsAutoFilterInstance::nsAutoFilterInstan
   filterRegion.RoundOut();
 
   if (filterRegion.Width() <= 0 || filterRegion.Height() <= 0) {
     // 0 disables rendering, < 0 is error. dispatch error console warning
     // or error as appropriate.
     return;
   }
 
-  nsCOMPtr<nsIDOMSVGMatrix> userToDeviceSpace =
-    NS_NewSVGMatrix(nsSVGUtils::GetCanvasTM(aTarget));
+  gfxMatrix userToDeviceSpace = nsSVGUtils::GetCanvasTM(aTarget);
   
   // Calculate filterRes (the width and height of the pixel buffer of the
   // temporary offscreen surface that we'll paint into):
 
   gfxIntSize filterRes;
   PRBool intOverflow;
 
   if (filter->HasAttr(kNameSpaceID_None, nsGkAtoms::filterRes)) {
@@ -178,26 +176,24 @@ nsAutoFilterInstance::nsAutoFilterInstan
     return;
   }
 
   // XXX we haven't taken account of the fact that filterRegion may be
   // partially or entirely outside the current clip region. :-/
 
   // Convert the dirty rects to filter space, and create our nsSVGFilterInstance:
 
-  nsCOMPtr<nsIDOMSVGMatrix> filterToUserSpace, filterToDeviceSpace;
-  NS_NewSVGMatrix(getter_AddRefs(filterToUserSpace),
-                  filterRegion.Width() / filterRes.width, 0.0f,
-                  0.0f, filterRegion.Height() / filterRes.height,
-                  filterRegion.X(), filterRegion.Y());
-  userToDeviceSpace->Multiply(filterToUserSpace, getter_AddRefs(filterToDeviceSpace));
+  gfxMatrix filterToUserSpace(filterRegion.Width() / filterRes.width, 0.0f,
+                              0.0f, filterRegion.Height() / filterRes.height,
+                              filterRegion.X(), filterRegion.Y());
+  gfxMatrix filterToDeviceSpace = filterToUserSpace * userToDeviceSpace;
   
   // filterToDeviceSpace is always invertible
-  gfxMatrix deviceToFilterSpace
-    = nsSVGUtils::ConvertSVGMatrixToThebes(filterToDeviceSpace).Invert();
+  gfxMatrix deviceToFilterSpace = filterToDeviceSpace;
+  deviceToFilterSpace.Invert();
 
   nsIntRect dirtyOutputRect =
     MapDeviceRectToFilterSpace(deviceToFilterSpace, filterRes, aDirtyOutputRect);
   nsIntRect dirtyInputRect =
     MapDeviceRectToFilterSpace(deviceToFilterSpace, filterRes, aDirtyInputRect);
 
   // Setup instance data
   mInstance = new nsSVGFilterInstance(aTarget, aPaint, filter, bbox, filterRegion,
@@ -229,18 +225,17 @@ nsSVGFilterFrame::FilterPaint(nsSVGRende
       result, instance.get()->GetFilterSpaceToDeviceSpaceTransform(), 1.0);
   }
   return rv;
 }
 
 static nsresult
 TransformFilterSpaceToDeviceSpace(nsSVGFilterInstance *aInstance, nsIntRect *aRect)
 {
-  gfxMatrix m = nsSVGUtils::ConvertSVGMatrixToThebes(
-    aInstance->GetFilterSpaceToDeviceSpaceTransform());
+  gfxMatrix m = aInstance->GetFilterSpaceToDeviceSpaceTransform();
   gfxRect r(aRect->x, aRect->y, aRect->width, aRect->height);
   r = m.TransformBounds(r);
   r.RoundOut();
   nsIntRect deviceRect;
   nsresult rv = nsSVGUtils::GfxRectToIntRect(r, &deviceRect);
   if (NS_FAILED(rv))
     return rv;
   *aRect = deviceRect;
--- a/layout/svg/base/src/nsSVGFilterInstance.cpp
+++ b/layout/svg/base/src/nsSVGFilterInstance.cpp
@@ -32,17 +32,16 @@
  * 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 "nsSVGFilterInstance.h"
 #include "nsSVGUtils.h"
 #include "nsIDOMSVGUnitTypes.h"
-#include "nsSVGMatrix.h"
 #include "gfxPlatform.h"
 #include "nsSVGFilterPaintCallback.h"
 #include "nsSVGFilterElement.h"
 
 static double Square(double aX)
 {
   return aX*aX;
 }
@@ -91,28 +90,24 @@ gfxRect
 nsSVGFilterInstance::UserSpaceToFilterSpace(const gfxRect& aRect) const
 {
   gfxRect r = aRect - mFilterRect.TopLeft();
   r.Scale(mFilterSpaceSize.width / mFilterRect.Width(),
           mFilterSpaceSize.height / mFilterRect.Height());
   return r;
 }
 
-already_AddRefed<nsIDOMSVGMatrix>
+gfxMatrix
 nsSVGFilterInstance::GetUserSpaceToFilterSpaceTransform() const
 {
-  nsCOMPtr<nsIDOMSVGMatrix> filterTransform;
   gfxFloat widthScale = mFilterSpaceSize.width / mFilterRect.Width();
   gfxFloat heightScale = mFilterSpaceSize.height / mFilterRect.Height();
-  NS_NewSVGMatrix(getter_AddRefs(filterTransform),
-                  widthScale, 0.0f,
-                  0.0f, heightScale,
-                  -mFilterRect.X() * widthScale,
-                  -mFilterRect.Y() * heightScale);
-  return filterTransform.forget();
+  return gfxMatrix(widthScale, 0.0f,
+                   0.0f, heightScale,
+                   -mFilterRect.X() * widthScale, -mFilterRect.Y() * heightScale);
 }
 
 void
 nsSVGFilterInstance::ComputeFilterPrimitiveSubregion(PrimitiveInfo* aPrimitive)
 {
   nsSVGFE* fE = aPrimitive->mFE;
 
   gfxRect defaultFilterSubregion(0,0,0,0);
@@ -336,22 +331,17 @@ nsSVGFilterInstance::BuildSourceImages()
       gfxPlatform::GetPlatform()->CreateOffscreenSurface(
               gfxIntSize(mSurfaceRect.width, mSurfaceRect.height),
               gfxASurface::ImageFormatARGB32);
     if (!offscreen || offscreen->CairoStatus())
       return NS_ERROR_OUT_OF_MEMORY;
     offscreen->SetDeviceOffset(gfxPoint(-mSurfaceRect.x, -mSurfaceRect.y));
   
     nsSVGRenderState tmpState(offscreen);
-    nsCOMPtr<nsIDOMSVGMatrix> userSpaceToFilterSpaceTransform
-      = GetUserSpaceToFilterSpaceTransform();
-    if (!userSpaceToFilterSpaceTransform)
-      return NS_ERROR_OUT_OF_MEMORY;
-    gfxMatrix userSpaceToFilterSpace =
-      nsSVGUtils::ConvertSVGMatrixToThebes(userSpaceToFilterSpaceTransform);
+    gfxMatrix userSpaceToFilterSpace = GetUserSpaceToFilterSpaceTransform();
 
     gfxRect r(neededRect.x, neededRect.y, neededRect.width, neededRect.height);
     gfxMatrix m = userSpaceToFilterSpace;
     m.Invert();
     r = m.TransformBounds(r);
     r.RoundOut();
     nsIntRect dirty;
     nsresult rv = nsSVGUtils::GfxRectToIntRect(r, &dirty);
@@ -364,18 +354,17 @@ nsSVGFilterInstance::BuildSourceImages()
     //
     // (In theory it would be better to minimize error by having filtered SVG
     // graphics temporarily paint to user space when painting the sources and
     // only set a user space to filter space transform on the gfxContext
     // (since that would elliminate the transform multiplications from user
     // space to device space and back again). However, that would make the
     // code more complex while being hard to get right without introducing
     // subtle bugs, and in practice it probably makes no real difference.)
-    gfxMatrix deviceToFilterSpace =
-      nsSVGUtils::ConvertSVGMatrixToThebes(GetFilterSpaceToDeviceSpaceTransform()).Invert();
+    gfxMatrix deviceToFilterSpace = GetFilterSpaceToDeviceSpaceTransform().Invert();
     tmpState.GetGfxContext()->Multiply(deviceToFilterSpace);
     mPaintCallback->Paint(&tmpState, mTargetFrame, &dirty);
 
     gfxContext copyContext(sourceColorAlpha);
     copyContext.SetSource(offscreen);
     copyContext.Paint();
   }
 
--- a/layout/svg/base/src/nsSVGFilterInstance.h
+++ b/layout/svg/base/src/nsSVGFilterInstance.h
@@ -67,17 +67,17 @@ public:
   float GetPrimitiveLength(nsSVGLength2 *aLength) const;
 
   nsSVGFilterInstance(nsIFrame *aTargetFrame,
                       nsSVGFilterPaintCallback *aPaintCallback,
                       nsSVGFilterElement *aFilterElement,
                       const gfxRect &aTargetBBox,
                       const gfxRect& aFilterRect,
                       const nsIntSize& aFilterSpaceSize,
-                      nsIDOMSVGMatrix *aFilterSpaceToDeviceSpaceTransform,
+                      const gfxMatrix &aFilterSpaceToDeviceSpaceTransform,
                       const nsIntRect& aDirtyOutputRect,
                       const nsIntRect& aDirtyInputRect,
                       PRUint16 aPrimitiveUnits) :
     mTargetFrame(aTargetFrame),
     mPaintCallback(aPaintCallback),
     mFilterElement(aFilterElement),
     mTargetBBox(aTargetBBox),
     mFilterSpaceToDeviceSpaceTransform(aFilterSpaceToDeviceSpaceTransform),
@@ -102,19 +102,19 @@ public:
   PRInt32 GetSurfaceWidth() const { return mSurfaceRect.width; }
   PRInt32 GetSurfaceHeight() const { return mSurfaceRect.height; }
   
   nsresult Render(gfxASurface** aOutput);
   nsresult ComputeOutputDirtyRect(nsIntRect* aDirty);
   nsresult ComputeSourceNeededRect(nsIntRect* aDirty);
   nsresult ComputeOutputBBox(nsIntRect* aBBox);
 
-  already_AddRefed<nsIDOMSVGMatrix> GetUserSpaceToFilterSpaceTransform() const;
-  nsIDOMSVGMatrix* GetFilterSpaceToDeviceSpaceTransform() const {
-    return mFilterSpaceToDeviceSpaceTransform.get();
+  gfxMatrix GetUserSpaceToFilterSpaceTransform() const;
+  gfxMatrix GetFilterSpaceToDeviceSpaceTransform() const {
+    return mFilterSpaceToDeviceSpaceTransform;
   }
 
 private:
   typedef nsSVGFE::Image Image;
   typedef nsSVGFE::ColorModel ColorModel;
 
   struct PrimitiveInfo {
     nsSVGFE*  mFE;
@@ -180,17 +180,17 @@ private:
     aRect->IntersectRect(*aRect, filterSpace);
   }
   void ClipToGfxRect(nsIntRect* aRect, const gfxRect& aGfx) const;
 
   nsIFrame*               mTargetFrame;
   nsSVGFilterPaintCallback* mPaintCallback;
   nsSVGFilterElement*     mFilterElement;
   gfxRect                 mTargetBBox;
-  nsCOMPtr<nsIDOMSVGMatrix> mFilterSpaceToDeviceSpaceTransform;
+  gfxMatrix               mFilterSpaceToDeviceSpaceTransform;
   gfxRect                 mFilterRect;
   nsIntSize               mFilterSpaceSize;
   nsIntRect               mDirtyOutputRect;
   nsIntRect               mDirtyInputRect;
   nsIntRect               mSurfaceRect;
   PRUint16                mPrimitiveUnits;
 
   PrimitiveInfo           mSourceColorAlpha;
--- a/layout/svg/base/src/nsSVGGFrame.cpp
+++ b/layout/svg/base/src/nsSVGGFrame.cpp
@@ -34,20 +34,20 @@
  * 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 "nsIDOMSVGTransformable.h"
 #include "nsSVGGFrame.h"
 #include "nsIFrame.h"
-#include "nsSVGMatrix.h"
 #include "nsGkAtoms.h"
 #include "nsSVGUtils.h"
 #include "nsSVGGraphicElement.h"
+#include "nsSVGMatrix.h"
 
 //----------------------------------------------------------------------
 // Implementation
 
 nsIFrame*
 NS_NewSVGGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {  
   return new (aPresShell) nsSVGGFrame(aContext);
--- a/layout/svg/base/src/nsSVGImageFrame.cpp
+++ b/layout/svg/base/src/nsSVGImageFrame.cpp
@@ -30,26 +30,25 @@
  * 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 "nsSVGPathGeometryFrame.h"
-#include "nsIDOMSVGMatrix.h"
 #include "imgIContainer.h"
 #include "nsStubImageDecoderObserver.h"
 #include "nsImageLoadingContent.h"
 #include "nsIDOMSVGImageElement.h"
 #include "nsLayoutUtils.h"
 #include "nsSVGImageElement.h"
 #include "nsSVGUtils.h"
-#include "nsSVGMatrix.h"
 #include "gfxContext.h"
+#include "gfxMatrix.h"
 #include "nsIInterfaceRequestorUtils.h"
 
 class nsSVGImageFrame;
 
 class nsSVGImageListener : public nsStubImageDecoderObserver
 {
 public:
   nsSVGImageListener(nsSVGImageFrame *aFrame);
@@ -106,17 +105,17 @@ public:
 #ifdef DEBUG
   NS_IMETHOD GetFrameName(nsAString& aResult) const
   {
     return MakeFrameName(NS_LITERAL_STRING("SVGImage"), aResult);
   }
 #endif
 
 private:
-  already_AddRefed<nsIDOMSVGMatrix> GetImageTransform();
+  gfxMatrix GetImageTransform();
 
   nsCOMPtr<imgIDecoderObserver> mListener;
 
   nsCOMPtr<imgIContainer> mImageContainer;
 
   friend class nsSVGImageListener;
 };
 
@@ -181,40 +180,33 @@ nsSVGImageFrame::AttributeChanged(PRInt3
      nsSVGUtils::UpdateGraphic(this);
      return NS_OK;
    }
 
    return nsSVGPathGeometryFrame::AttributeChanged(aNameSpaceID,
                                                    aAttribute, aModType);
 }
 
-already_AddRefed<nsIDOMSVGMatrix>
+gfxMatrix
 nsSVGImageFrame::GetImageTransform()
 {
-  nsCOMPtr<nsIDOMSVGMatrix> ctm = NS_NewSVGMatrix(GetCanvasTM());
-
   float x, y, width, height;
   nsSVGImageElement *element = static_cast<nsSVGImageElement*>(mContent);
   element->GetAnimatedLengthValues(&x, &y, &width, &height, nsnull);
 
   PRInt32 nativeWidth, nativeHeight;
   mImageContainer->GetWidth(&nativeWidth);
   mImageContainer->GetHeight(&nativeHeight);
 
-  nsCOMPtr<nsIDOMSVGMatrix> trans, ctmXY, fini;
-  trans = nsSVGUtils::GetViewBoxTransform(width, height,
-                                          0, 0,
-                                          nativeWidth, nativeHeight,
-                                          element->mPreserveAspectRatio);
-  ctm->Translate(x, y, getter_AddRefs(ctmXY));
-  ctmXY->Multiply(trans, getter_AddRefs(fini));
+  gfxMatrix viewBoxTM =
+    nsSVGUtils::GetViewBoxTransform(width, height,
+                                    0, 0, nativeWidth, nativeHeight,
+                                    element->mPreserveAspectRatio);
 
-  nsIDOMSVGMatrix *retval = nsnull;
-  fini.swap(retval);
-  return retval;
+  return viewBoxTM * gfxMatrix().Translate(gfxPoint(x, y)) * GetCanvasTM();
 }
 
 //----------------------------------------------------------------------
 // nsISVGChildFrame methods:
 NS_IMETHODIMP
 nsSVGImageFrame::PaintSVG(nsSVGRenderState *aContext,
                           const nsIntRect *aDirtyRect)
 {
@@ -259,50 +251,47 @@ nsSVGImageFrame::PaintSVG(nsSVGRenderSta
     if (GetStyleDisplay()->IsScrollableOverflow()) {
       gfx->Save();
 
       gfxRect clipRect =
         nsSVGUtils::GetClipRectForFrame(this, x, y, width, height);
       nsSVGUtils::SetClipRect(gfx, GetCanvasTM(), clipRect);
     }
 
-    nsCOMPtr<nsIDOMSVGMatrix> fini = GetImageTransform();
-
     // fill-opacity doesn't affect <image>, so if we're allowed to
     // optimize group opacity, the opacity used for compositing the
     // image into the current canvas is just the group opacity.
     float opacity = 1.0f;
     if (nsSVGUtils::CanOptimizeOpacity(this)) {
       opacity = GetStyleDisplay()->mOpacity;
     }
 
     PRInt32 nativeWidth, nativeHeight;
     mImageContainer->GetWidth(&nativeWidth);
     mImageContainer->GetHeight(&nativeHeight);
 
-    nsSVGUtils::CompositePatternMatrix(gfx, thebesPattern, fini, nativeWidth, nativeHeight, opacity);
+    nsSVGUtils::CompositePatternMatrix(gfx, thebesPattern, GetImageTransform(),
+                                       nativeWidth, nativeHeight, opacity);
 
     if (GetStyleDisplay()->IsScrollableOverflow())
       gfx->Restore();
   }
 
   return rv;
 }
 
 NS_IMETHODIMP_(nsIFrame*)
 nsSVGImageFrame::GetFrameForPoint(const nsPoint &aPoint)
 {
   if (GetStyleDisplay()->IsScrollableOverflow() && mImageContainer) {
     PRInt32 nativeWidth, nativeHeight;
     mImageContainer->GetWidth(&nativeWidth);
     mImageContainer->GetHeight(&nativeHeight);
 
-    nsCOMPtr<nsIDOMSVGMatrix> fini = GetImageTransform();
-
-    if (!nsSVGUtils::HitTestRect(fini,
+    if (!nsSVGUtils::HitTestRect(GetImageTransform(),
                                  0, 0, nativeWidth, nativeHeight,
                                  PresContext()->AppUnitsToDevPixels(aPoint.x),
                                  PresContext()->AppUnitsToDevPixels(aPoint.y))) {
       return nsnull;
     }
   }
 
   return nsSVGPathGeometryFrame::GetFrameForPoint(aPoint);
--- a/layout/svg/base/src/nsSVGInnerSVGFrame.cpp
+++ b/layout/svg/base/src/nsSVGInnerSVGFrame.cpp
@@ -154,27 +154,23 @@ nsSVGInnerSVGFrame::NotifySVGChanged(PRU
 
   nsSVGInnerSVGFrameBase::NotifySVGChanged(aFlags);
 }
 
 NS_IMETHODIMP_(nsIFrame*)
 nsSVGInnerSVGFrame::GetFrameForPoint(const nsPoint &aPoint)
 {
   if (GetStyleDisplay()->IsScrollableOverflow()) {
-    float clipX, clipY, clipWidth, clipHeight;
-    nsCOMPtr<nsIDOMSVGMatrix> clipTransform;
-
-    nsSVGElement *svg = static_cast<nsSVGElement*>(mContent);
-    svg->GetAnimatedLengthValues(&clipX, &clipY, &clipWidth, &clipHeight, nsnull);
+    nsSVGElement *content = static_cast<nsSVGElement*>(mContent);
+    nsSVGContainerFrame *parent = static_cast<nsSVGContainerFrame*>(mParent);
 
-    nsSVGContainerFrame *parent = static_cast<nsSVGContainerFrame*>
-                                             (mParent);
-    clipTransform = NS_NewSVGMatrix(parent->GetCanvasTM());
+    float clipX, clipY, clipWidth, clipHeight;
+    content->GetAnimatedLengthValues(&clipX, &clipY, &clipWidth, &clipHeight, nsnull);
 
-    if (!nsSVGUtils::HitTestRect(clipTransform,
+    if (!nsSVGUtils::HitTestRect(parent->GetCanvasTM(),
                                  clipX, clipY, clipWidth, clipHeight,
                                  PresContext()->AppUnitsToDevPixels(aPoint.x),
                                  PresContext()->AppUnitsToDevPixels(aPoint.y))) {
       return nsnull;
     }
   }
 
   return nsSVGInnerSVGFrameBase::GetFrameForPoint(aPoint);
--- a/layout/svg/base/src/nsSVGIntegrationUtils.cpp
+++ b/layout/svg/base/src/nsSVGIntegrationUtils.cpp
@@ -37,17 +37,16 @@
 
 #include "nsSVGIntegrationUtils.h"
 
 #include "nsSVGUtils.h"
 #include "nsSVGEffects.h"
 #include "nsRegion.h"
 #include "nsLayoutUtils.h"
 #include "nsDisplayList.h"
-#include "nsSVGMatrix.h"
 #include "nsSVGFilterPaintCallback.h"
 #include "nsSVGFilterFrame.h"
 #include "nsSVGClipPathFrame.h"
 #include "nsSVGMaskFrame.h"
 
 // ----------------------------------------------------------------------
 
 PRBool
@@ -279,17 +278,17 @@ nsSVGIntegrationUtils::PaintFramesWithEf
   gfxMatrix savedCTM = gfx->CurrentMatrix();
   nsSVGRenderState svgContext(aCtx);
 
   nsRect userSpaceRect = GetNonSVGUserSpace(firstFrame) + aBuilder->ToReferenceFrame(firstFrame);
   PRInt32 appUnitsPerDevPixel = aEffectsFrame->PresContext()->AppUnitsPerDevPixel();
   userSpaceRect = userSpaceRect.ToNearestPixels(appUnitsPerDevPixel).ToAppUnits(appUnitsPerDevPixel);
   aCtx->Translate(userSpaceRect.x, userSpaceRect.y);
 
-  nsCOMPtr<nsIDOMSVGMatrix> matrix = GetInitialMatrix(aEffectsFrame);
+  gfxMatrix matrix = GetInitialMatrix(aEffectsFrame);
 
   PRBool complexEffects = PR_FALSE;
   /* Check if we need to do additional operations on this child's
    * rendering, which necessitates rendering into another surface. */
   if (opacity != 1.0f || maskFrame || (clipPathFrame && !isTrivialClip)) {
     complexEffects = PR_TRUE;
     gfx->Save();
     gfx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
@@ -354,29 +353,28 @@ nsSVGIntegrationUtils::PaintFramesWithEf
   } else if (opacity != 1.0f) {
     gfx->Paint(opacity);
   }
 
   gfx->Restore();
   gfx->SetMatrix(savedCTM);
 }
 
-already_AddRefed<nsIDOMSVGMatrix>
+gfxMatrix
 nsSVGIntegrationUtils::GetInitialMatrix(nsIFrame* aNonSVGFrame)
 {
   NS_ASSERTION(!aNonSVGFrame->IsFrameOfType(nsIFrame::eSVG),
                "SVG frames should not get here");
   PRInt32 appUnitsPerDevPixel = aNonSVGFrame->PresContext()->AppUnitsPerDevPixel();
-  nsCOMPtr<nsIDOMSVGMatrix> matrix;
   float devPxPerCSSPx =
     1 / nsPresContext::AppUnitsToFloatCSSPixels(appUnitsPerDevPixel);
-  NS_NewSVGMatrix(getter_AddRefs(matrix),
-                  devPxPerCSSPx, 0.0f,
-                  0.0f, devPxPerCSSPx);
-  return matrix.forget();
+
+  return gfxMatrix(devPxPerCSSPx, 0.0,
+                   0.0, devPxPerCSSPx,
+                   0.0, 0.0);
 }
 
 gfxRect
 nsSVGIntegrationUtils::GetSVGRectForNonSVGFrame(nsIFrame* aNonSVGFrame)
 {
   NS_ASSERTION(!aNonSVGFrame->IsFrameOfType(nsIFrame::eSVG),
                "SVG frames should not get here");
   nsIFrame* firstFrame =
--- a/layout/svg/base/src/nsSVGIntegrationUtils.h
+++ b/layout/svg/base/src/nsSVGIntegrationUtils.h
@@ -36,22 +36,22 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef NSSVGINTEGRATIONUTILS_H_
 #define NSSVGINTEGRATIONUTILS_H_
 
 #include "nsPoint.h"
 #include "nsRect.h"
 #include "gfxRect.h"
+#include "gfxMatrix.h"
 
 class nsIFrame;
 class nsDisplayListBuilder;
 class nsDisplayList;
 class nsIRenderingContext;
-class nsIDOMSVGMatrix;
 
 /***** Integration of SVG effects with regular frame painting *****/
 
 class nsSVGIntegrationUtils
 {
 public:
   /**
    * Returns true if a non-SVG frame has SVG effects.
@@ -92,17 +92,17 @@ public:
    * in aCtx's coordinate system
    */
   static void
   PaintFramesWithEffects(nsIRenderingContext* aCtx,
                          nsIFrame* aEffectsFrame, const nsRect& aDirtyRect,
                          nsDisplayListBuilder* aBuilder,
                          nsDisplayList* aInnerList);
 
-  static already_AddRefed<nsIDOMSVGMatrix>
+  static gfxMatrix
   GetInitialMatrix(nsIFrame* aNonSVGFrame);
   /**
    * Returns aNonSVGFrame's rect in CSS pixel units. This is the union
    * of all its continuations' rectangles. The top-left is always 0,0
    * since "user space" origin for non-SVG frames is the top-left of the
    * union of all the continuations' rectangles.
    */
   static gfxRect
--- a/layout/svg/base/src/nsSVGMarkerFrame.cpp
+++ b/layout/svg/base/src/nsSVGMarkerFrame.cpp
@@ -34,17 +34,16 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsIDOMSVGAnimatedRect.h"
 #include "nsIDOMSVGRect.h"
 #include "nsIDocument.h"
 #include "nsSVGMarkerFrame.h"
 #include "nsSVGPathGeometryFrame.h"
-#include "nsSVGMatrix.h"
 #include "nsSVGEffects.h"
 #include "nsSVGMarkerElement.h"
 #include "nsSVGPathGeometryElement.h"
 #include "gfxContext.h"
 
 nsIFrame*
 NS_NewSVGMarkerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
@@ -108,28 +107,20 @@ nsSVGMarkerFrame::GetCanvasTM()
   }
 
   nsSVGMarkerElement *content = static_cast<nsSVGMarkerElement*>(mContent);
   
   mInUse2 = PR_TRUE;
   gfxMatrix markedTM = mMarkedFrame->GetCanvasTM();
   mInUse2 = PR_FALSE;
 
-  nsCOMPtr<nsIDOMSVGMatrix> markerTM;
-  content->GetMarkerTransform(mStrokeWidth, mX, mY, mAngle, getter_AddRefs(markerTM));
+  gfxMatrix markerTM = content->GetMarkerTransform(mStrokeWidth, mX, mY, mAngle);
+  gfxMatrix viewBoxTM = content->GetViewBoxTransform();
 
-  nsCOMPtr<nsIDOMSVGMatrix> viewBoxTM;
-  nsresult res = content->GetViewboxToViewportTransform(getter_AddRefs(viewBoxTM));
-  if (NS_FAILED(res)) {
-    return gfxMatrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); // singular
-  }
-
-  markedTM.PreMultiply(nsSVGUtils::ConvertSVGMatrixToThebes(markerTM));
-  markedTM.PreMultiply(nsSVGUtils::ConvertSVGMatrixToThebes(viewBoxTM));
-  return markedTM;
+  return viewBoxTM * markerTM * markedTM;
 }
 
 
 nsresult
 nsSVGMarkerFrame::PaintMark(nsSVGRenderState *aContext,
                             nsSVGPathGeometryFrame *aMarkedFrame,
                             nsSVGMark *aMark, float aStrokeWidth)
 {
--- a/layout/svg/base/src/nsSVGMaskFrame.cpp
+++ b/layout/svg/base/src/nsSVGMaskFrame.cpp
@@ -36,30 +36,31 @@
 
 #include "nsIDocument.h"
 #include "nsSVGMaskFrame.h"
 #include "nsSVGContainerFrame.h"
 #include "nsSVGMaskElement.h"
 #include "nsIDOMSVGMatrix.h"
 #include "gfxContext.h"
 #include "gfxImageSurface.h"
+#include "nsSVGMatrix.h"
 
 //----------------------------------------------------------------------
 // Implementation
 
 nsIFrame*
 NS_NewSVGMaskFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsSVGMaskFrame(aContext);
 }
 
 already_AddRefed<gfxPattern>
 nsSVGMaskFrame::ComputeMaskAlpha(nsSVGRenderState *aContext,
                                  nsIFrame* aParent,
-                                 nsIDOMSVGMatrix* aMatrix,
+                                 const gfxMatrix &aMatrix,
                                  float aOpacity)
 {
   // If the flag is set when we get here, it means this mask frame
   // has already been used painting the current mask, and the document
   // has a mask reference loop.
   if (mInUse) {
     NS_WARNING("Mask loop detected!");
     return nsnull;
@@ -79,21 +80,21 @@ nsSVGMaskFrame::ComputeMaskAlpha(nsSVGRe
     if (units == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
       bbox = nsSVGUtils::GetBBox(aParent);
     }
 
     gfxRect maskArea = nsSVGUtils::GetRelativeRect(units,
       &mask->mLengthAttributes[nsSVGMaskElement::X], bbox, aParent);
 
     gfx->Save();
-    nsSVGUtils::SetClipRect(gfx, nsSVGUtils::ConvertSVGMatrixToThebes(aMatrix), maskArea);
+    nsSVGUtils::SetClipRect(gfx, aMatrix, maskArea);
   }
 
   mMaskParent = aParent;
-  mMaskParentMatrix = aMatrix;
+  mMaskParentMatrix = NS_NewSVGMatrix(aMatrix);
 
   for (nsIFrame* kid = mFrames.FirstChild(); kid;
        kid = kid->GetNextSibling()) {
     nsSVGUtils::PaintFrameWithEffects(aContext, nsnull, kid);
   }
 
   gfxRect clipExtents = gfx->GetClipExtents();
   gfx->Restore();
@@ -180,16 +181,13 @@ nsSVGMaskFrame::GetType() const
 
 gfxMatrix
 nsSVGMaskFrame::GetCanvasTM()
 {
   NS_ASSERTION(mMaskParentMatrix, "null parent matrix");
 
   nsSVGMaskElement *mask = static_cast<nsSVGMaskElement*>(mContent);
 
-  nsCOMPtr<nsIDOMSVGMatrix> matrix =
-         nsSVGUtils::AdjustMatrixForUnits(mMaskParentMatrix,
+  return nsSVGUtils::AdjustMatrixForUnits(nsSVGUtils::ConvertSVGMatrixToThebes(mMaskParentMatrix),
                                           &mask->mEnumAttributes[nsSVGMaskElement::MASKCONTENTUNITS],
                                           mMaskParent);
-  
-  return nsSVGUtils::ConvertSVGMatrixToThebes(matrix);
 }
 
--- a/layout/svg/base/src/nsSVGMaskFrame.h
+++ b/layout/svg/base/src/nsSVGMaskFrame.h
@@ -54,17 +54,17 @@ protected:
     nsSVGMaskFrameBase(aContext),
     mMaskParentMatrix(nsnull),
     mInUse(PR_FALSE) {}
 
 public:
   // nsSVGMaskFrame method:
   already_AddRefed<gfxPattern> ComputeMaskAlpha(nsSVGRenderState *aContext,
                                                 nsIFrame* aParent,
-                                                nsIDOMSVGMatrix* aMatrix,
+                                                const gfxMatrix &aMatrix,
                                                 float aOpacity = 1.0f);
 
 #ifdef DEBUG
   NS_IMETHOD Init(nsIContent*      aContent,
                   nsIFrame*        aParent,
                   nsIFrame*        aPrevInFlow);
 #endif
 
--- a/layout/svg/base/src/nsSVGOuterSVGFrame.cpp
+++ b/layout/svg/base/src/nsSVGOuterSVGFrame.cpp
@@ -736,51 +736,33 @@ nsSVGOuterSVGFrame::NotifyViewportChange
 
 //----------------------------------------------------------------------
 // nsSVGContainerFrame methods:
 
 gfxMatrix
 nsSVGOuterSVGFrame::GetCanvasTM()
 {
   if (!mCanvasTM) {
-    nsSVGSVGElement *svgElement = static_cast<nsSVGSVGElement*>(mContent);
+    nsSVGSVGElement *content = static_cast<nsSVGSVGElement*>(mContent);
 
     float devPxPerCSSPx =
-      1 / PresContext()->AppUnitsToFloatCSSPixels(
+      1.0f / PresContext()->AppUnitsToFloatCSSPixels(
                                 PresContext()->AppUnitsPerDevPixel());
-    nsCOMPtr<nsIDOMSVGMatrix> devPxToCSSPxMatrix;
-    NS_NewSVGMatrix(getter_AddRefs(devPxToCSSPxMatrix),
-                    devPxPerCSSPx, 0.0f,
-                    0.0f, devPxPerCSSPx);
+
+    gfxMatrix viewBoxTM = content->GetViewBoxTransform();
 
-    nsCOMPtr<nsIDOMSVGMatrix> viewBoxTM;
-    nsresult res =
-      svgElement->GetViewboxToViewportTransform(getter_AddRefs(viewBoxTM));
-    if (NS_SUCCEEDED(res) && viewBoxTM) {
-      // PRE-multiply px conversion!
-      devPxToCSSPxMatrix->Multiply(viewBoxTM, getter_AddRefs(mCanvasTM));
-    } else {
-      NS_WARNING("We should propagate the fact that the viewBox is invalid.");
-      mCanvasTM = devPxToCSSPxMatrix;
+    gfxMatrix zoomPanTM;
+    if (mIsRootContent) {
+      const nsSVGTranslatePoint& translate = content->GetCurrentTranslate();
+      zoomPanTM.Translate(gfxPoint(translate.GetX(), translate.GetY()));
+      zoomPanTM.Scale(content->GetCurrentScale(), content->GetCurrentScale());
     }
 
-    // our content is the document element so we must premultiply the values
-    // of its currentScale and currentTranslate properties
-    if (mIsRootContent) {
-      nsCOMPtr<nsIDOMSVGMatrix> zoomPanMatrix;
-      nsCOMPtr<nsIDOMSVGMatrix> temp;
-      float scale = svgElement->GetCurrentScale();
-      const nsSVGTranslatePoint& translate = svgElement->GetCurrentTranslate();
-
-      svgElement->CreateSVGMatrix(getter_AddRefs(zoomPanMatrix));
-      zoomPanMatrix->Translate(translate.GetX(), translate.GetY(), getter_AddRefs(temp));
-      temp->Scale(scale, getter_AddRefs(zoomPanMatrix));
-      zoomPanMatrix->Multiply(mCanvasTM, getter_AddRefs(temp));
-      temp.swap(mCanvasTM);
-    }
+    gfxMatrix TM = viewBoxTM * zoomPanTM * gfxMatrix().Scale(devPxPerCSSPx, devPxPerCSSPx);
+    mCanvasTM = NS_NewSVGMatrix(TM);
   }
   return nsSVGUtils::ConvertSVGMatrixToThebes(mCanvasTM);
 }
 
 //----------------------------------------------------------------------
 // Implementation helpers
 
 void
--- a/layout/svg/base/src/nsSVGPathGeometryFrame.cpp
+++ b/layout/svg/base/src/nsSVGPathGeometryFrame.cpp
@@ -34,17 +34,16 @@
  * 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 "nsSVGPathGeometryFrame.h"
 #include "nsGkAtoms.h"
 #include "nsSVGMarkerFrame.h"
-#include "nsSVGMatrix.h"
 #include "nsSVGUtils.h"
 #include "nsSVGEffects.h"
 #include "nsSVGGraphicElement.h"
 #include "nsSVGOuterSVGFrame.h"
 #include "nsSVGRect.h"
 #include "nsSVGPathGeometryElement.h"
 #include "gfxContext.h"
 
--- a/layout/svg/base/src/nsSVGPathGeometryFrame.h
+++ b/layout/svg/base/src/nsSVGPathGeometryFrame.h
@@ -43,17 +43,16 @@
 #include "nsISVGChildFrame.h"
 #include "nsWeakReference.h"
 #include "nsGkAtoms.h"
 #include "nsSVGGeometryFrame.h"
 #include "gfxRect.h"
 #include "gfxMatrix.h"
 
 class nsPresContext;
-class nsIDOMSVGMatrix;
 class nsSVGMarkerFrame;
 class nsSVGMarkerProperty;
 
 typedef nsSVGGeometryFrame nsSVGPathGeometryFrameBase;
 
 #define HITTEST_MASK_FILL        0x01
 #define HITTEST_MASK_STROKE      0x02
 #define HITTEST_MASK_FORCE_TEST  0x04
--- a/layout/svg/base/src/nsSVGPatternFrame.cpp
+++ b/layout/svg/base/src/nsSVGPatternFrame.cpp
@@ -49,16 +49,17 @@
 #include "nsSVGEffects.h"
 #include "nsSVGOuterSVGFrame.h"
 #include "nsSVGPatternElement.h"
 #include "nsSVGGeometryFrame.h"
 #include "nsSVGPatternFrame.h"
 #include "gfxContext.h"
 #include "gfxPlatform.h"
 #include "gfxPattern.h"
+#include "gfxMatrix.h"
 
 
 //----------------------------------------------------------------------
 // Implementation
 
 nsSVGPatternFrame::nsSVGPatternFrame(nsStyleContext* aContext) :
   nsSVGPatternFrameBase(aContext),
   mLoopFlag(PR_FALSE), mPaintLoopFlag(PR_FALSE),
@@ -192,26 +193,29 @@ nsSVGPatternFrame::PaintPattern(gfxASurf
    *      to get the renderer to handle the translations correctly for us.
    *   3) The CTM that we return to our children who make up the pattern.
    */
 
   // Get all of the information we need from our "caller" -- i.e.
   // the geometry that is being rendered with a pattern
   nsSVGElement *callerContent;
   gfxRect callerBBox;
-  nsCOMPtr<nsIDOMSVGMatrix> callerCTM;
-  if (NS_FAILED(GetTargetGeometry(getter_AddRefs(callerCTM),
+  gfxMatrix callerCTM;
+  if (NS_FAILED(GetTargetGeometry(&callerCTM,
                                   &callerBBox,
                                   &callerContent, aSource)))
     return NS_ERROR_FAILURE;
 
   // Construct the CTM that we will provide to our children when we
   // render them into the tile.
-  if (NS_FAILED(ConstructCTM(getter_AddRefs(mCTM), callerBBox, callerCTM)))
+  gfxMatrix ctm = ConstructCTM(callerBBox, callerCTM);
+  if (ctm.IsSingular()) {
     return NS_ERROR_FAILURE;
+  }
+  mCTM = NS_NewSVGMatrix(ctm).get();
 
   // Get the bounding box of the pattern.  This will be used to determine
   // the size of the surface, and will also be used to define the bounding
   // box for the pattern tile.
   gfxRect bbox = GetPatternRect(callerBBox, callerCTM, callerContent);
 
   // Get the transformation matrix that we will hand to the renderer's pattern
   // routine.
@@ -469,17 +473,17 @@ nsSVGPatternFrame::GetPatternWithAttr(ns
 }
 
 // -------------------------------------------------------------------------
 // Helper functions
 // -------------------------------------------------------------------------
 
 gfxRect
 nsSVGPatternFrame::GetPatternRect(const gfxRect &aTargetBBox,
-                                  nsIDOMSVGMatrix *aTargetCTM,
+                                  const gfxMatrix &aTargetCTM,
                                   nsSVGElement *aTarget)
 {
   // Get our type
   PRUint16 type = GetPatternUnits();
 
   // We need to initialize our box
   float x,y,width,height;
 
@@ -507,62 +511,52 @@ nsSVGPatternFrame::GetPatternRect(const 
 }
 
 static float
 GetLengthValue(const nsSVGLength2 *aLength)
 {
   return aLength->GetAnimValue(static_cast<nsSVGSVGElement*>(nsnull));
 }
 
-nsresult
-nsSVGPatternFrame::ConstructCTM(nsIDOMSVGMatrix **aCTM,
-                                const gfxRect &callerBBox,
-                                nsIDOMSVGMatrix *callerCTM)
+gfxMatrix
+nsSVGPatternFrame::ConstructCTM(const gfxRect &callerBBox,
+                                const gfxMatrix &callerCTM)
 {
-  nsCOMPtr<nsIDOMSVGMatrix> tCTM, tempTM;
+  gfxMatrix tCTM;
 
-  // Begin by handling the objectBoundingBox conversion since
-  // this must be handled in the CTM
-  PRUint16 type = GetPatternContentUnits();
-
-  if (type == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
-    NS_NewSVGMatrix(getter_AddRefs(tCTM), callerBBox.Width(), 0.0f, 0.0f,
-                    callerBBox.Height(), 0.0f, 0.0f);
+  // The objectBoundingBox conversion must be handled in the CTM:
+  if (GetPatternContentUnits() ==
+      nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
+    tCTM.Scale(callerBBox.Width(), callerBBox.Height());
   } else {
     float scale = nsSVGUtils::MaxExpansion(callerCTM);
-    NS_NewSVGMatrix(getter_AddRefs(tCTM), scale, 0, 0, scale, 0, 0);
+    tCTM.Scale(scale, scale);
   }
 
+  gfxMatrix viewBoxTM;
   const nsSVGViewBoxRect viewBox = GetViewBox().GetAnimValue();
 
   if (viewBox.height > 0.0f && viewBox.width > 0.0f) {
-
     float viewportWidth = GetLengthValue(GetWidth());
     float viewportHeight = GetLengthValue(GetHeight());
     float refX = GetLengthValue(GetX());
     float refY = GetLengthValue(GetY());
-
-    tempTM = nsSVGUtils::GetViewBoxTransform(viewportWidth, viewportHeight,
-                                             viewBox.x + refX, viewBox.y + refY,
-                                             viewBox.width, viewBox.height,
-                                             GetPreserveAspectRatio(),
-                                             PR_TRUE);
-
-  } else {
-    // No viewBox, construct from the (modified) parent matrix
-    NS_NewSVGMatrix(getter_AddRefs(tempTM));
+    viewBoxTM = nsSVGUtils::GetViewBoxTransform(viewportWidth, viewportHeight,
+                                                viewBox.x + refX, viewBox.y + refY,
+                                                viewBox.width, viewBox.height,
+                                                GetPreserveAspectRatio(),
+                                                PR_TRUE);
   }
-  tCTM->Multiply(tempTM, aCTM);
-  return NS_OK;
+  return viewBoxTM * tCTM;
 }
 
 gfxMatrix
 nsSVGPatternFrame::GetPatternMatrix(const gfxRect &bbox,
                                     const gfxRect &callerBBox,
-                                    nsIDOMSVGMatrix *callerCTM)
+                                    const gfxMatrix &callerCTM)
 {
   // Get the pattern transform
   gfxMatrix patternTransform = GetPatternTransform();
 
   // We really want the pattern matrix to handle translations
   float minx = bbox.X();
   float miny = bbox.Y();
 
@@ -575,22 +569,21 @@ nsSVGPatternFrame::GetPatternMatrix(cons
   float scale = 1.0f / nsSVGUtils::MaxExpansion(callerCTM);
   patternTransform.Scale(scale, scale);
   patternTransform.Translate(gfxPoint(minx, miny));
 
   return patternTransform;
 }
 
 nsresult
-nsSVGPatternFrame::GetTargetGeometry(nsIDOMSVGMatrix **aCTM,
+nsSVGPatternFrame::GetTargetGeometry(gfxMatrix *aCTM,
                                      gfxRect *aBBox,
                                      nsSVGElement **aTargetContent,
                                      nsSVGGeometryFrame *aTarget)
 {
-  *aCTM = nsnull;
   *aTargetContent = nsnull;
 
   // Make sure the callerContent is an SVG element.  If we are attempting
   // to paint a pattern for text, then the content will be the #text, so we
   // actually want the parent, which should be the <svg:text> or <svg:tspan>
   // element.
   nsIAtom *callerType = aTarget->GetType();
   if (callerType ==  nsGkAtoms::svgGlyphFrame) {
@@ -613,17 +606,17 @@ nsSVGPatternFrame::GetTargetGeometry(nsI
   PRUint16 type = GetPatternUnits();
   if (type == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
     if (aBBox->Width() <= 0 || aBBox->Height() <= 0) {
       return NS_ERROR_FAILURE;
     }
   }
 
   // Get the transformation matrix from our calling geometry
-  *aCTM = NS_NewSVGMatrix(aTarget->GetCanvasTM()).get();
+  *aCTM = aTarget->GetCanvasTM();
 
   // OK, now fix up the bounding box to reflect user coordinates
   // We handle device unit scaling in pattern matrix
   {
     float scale = nsSVGUtils::MaxExpansion(*aCTM);
     if (scale <= 0) {
       return NS_ERROR_FAILURE;
     }
--- a/layout/svg/base/src/nsSVGPatternFrame.h
+++ b/layout/svg/base/src/nsSVGPatternFrame.h
@@ -124,25 +124,24 @@ protected:
   PRUint16 GetPatternContentUnits();
   gfxMatrix GetPatternTransform();
 
   const nsSVGViewBox &GetViewBox();
   const nsSVGPreserveAspectRatio &GetPreserveAspectRatio();
 
   NS_IMETHOD GetPatternFirstChild(nsIFrame **kid);
   gfxRect    GetPatternRect(const gfxRect &bbox,
-                            nsIDOMSVGMatrix *callerCTM,
+                            const gfxMatrix &callerCTM,
                             nsSVGElement *content);
   gfxMatrix  GetPatternMatrix(const gfxRect &bbox,
                               const gfxRect &callerBBox,
-                              nsIDOMSVGMatrix *callerCTM);
-  nsresult   ConstructCTM(nsIDOMSVGMatrix **ctm,
-                          const gfxRect &callerBBox,
-                          nsIDOMSVGMatrix *callerCTM);
-  nsresult   GetTargetGeometry(nsIDOMSVGMatrix **aCTM,
+                              const gfxMatrix &callerCTM);
+  gfxMatrix  ConstructCTM(const gfxRect &callerBBox,
+                          const gfxMatrix &callerCTM);
+  nsresult   GetTargetGeometry(gfxMatrix *aCTM,
                                gfxRect *aBBox,
                                nsSVGElement **aTargetContent,
                                nsSVGGeometryFrame *aTarget);
 
 private:
   // this is a *temporary* reference to the frame of the element currently
   // referencing our pattern.  This must be temporary because different
   // referencing frames will all reference this one frame
--- a/layout/svg/base/src/nsSVGTSpanFrame.cpp
+++ b/layout/svg/base/src/nsSVGTSpanFrame.cpp
@@ -36,17 +36,16 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsIDOMSVGTSpanElement.h"
 #include "nsSVGTSpanFrame.h"
 #include "nsSVGUtils.h"
 #include "nsSVGTextFrame.h"
 #include "nsSVGOuterSVGFrame.h"
-#include "nsSVGMatrix.h"
 
 //----------------------------------------------------------------------
 // Implementation
 
 nsIFrame*
 NS_NewSVGTSpanFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsSVGTSpanFrame(aContext);
--- a/layout/svg/base/src/nsSVGTextContainerFrame.cpp
+++ b/layout/svg/base/src/nsSVGTextContainerFrame.cpp
@@ -32,17 +32,16 @@
  * 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 "nsSVGContainerFrame.h"
 #include "nsSVGTextFrame.h"
 #include "nsSVGUtils.h"
-#include "nsSVGMatrix.h"
 #include "nsSVGOuterSVGFrame.h"
 #include "nsIDOMSVGTextElement.h"
 #include "nsIDOMSVGAnimatedLengthList.h"
 #include "nsISVGGlyphFragmentLeaf.h"
 #include "nsDOMError.h"
 
 //----------------------------------------------------------------------
 // nsQueryFrame methods
--- a/layout/svg/base/src/nsSVGTextPathFrame.cpp
+++ b/layout/svg/base/src/nsSVGTextPathFrame.cpp
@@ -37,17 +37,16 @@
 #include "nsSVGTextPathFrame.h"
 #include "nsIDOMSVGTextPathElement.h"
 #include "nsSVGLength2.h"
 #include "nsIDOMSVGURIReference.h"
 #include "nsSVGEffects.h"
 #include "nsContentUtils.h"
 #include "nsSVGPathElement.h"
 #include "nsSVGTextPathElement.h"
-#include "nsSVGMatrix.h"
 
 //----------------------------------------------------------------------
 // Implementation
 
 nsIFrame*
 NS_NewSVGTextPathFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsSVGTextPathFrame(aContext);
@@ -148,23 +147,21 @@ nsSVGTextPathFrame::GetFlattenedPath()
   nsIFrame *path = GetPathFrame();
   return path ? GetFlattenedPath(path) : nsnull;
 }
  
 already_AddRefed<gfxFlattenedPath>
 nsSVGTextPathFrame::GetFlattenedPath(nsIFrame *path)
 {
   NS_PRECONDITION(path, "Unexpected null path");
-  nsSVGPathGeometryElement *element = static_cast<nsSVGPathGeometryElement*>
-                                                 (path->GetContent());
 
-  nsCOMPtr<nsIDOMSVGMatrix> localTM =
-    NS_NewSVGMatrix(element->PrependLocalTransformTo(gfxMatrix()));
+  nsSVGPathGeometryElement *element =
+    static_cast<nsSVGPathGeometryElement*>(path->GetContent());
 
-  return element->GetFlattenedPath(localTM);
+  return element->GetFlattenedPath(element->PrependLocalTransformTo(gfxMatrix()));
 }
 
 gfxFloat
 nsSVGTextPathFrame::GetStartOffset()
 {
   nsSVGTextPathElement *tp = static_cast<nsSVGTextPathElement*>(mContent);
   nsSVGLength2 *length = &tp->mLengthAttributes[nsSVGTextPathElement::STARTOFFSET];
   float val = length->GetAnimValInSpecifiedUnits();
--- a/layout/svg/base/src/nsSVGUseFrame.cpp
+++ b/layout/svg/base/src/nsSVGUseFrame.cpp
@@ -31,17 +31,16 @@
  * 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 "nsSVGGFrame.h"
 #include "nsIAnonymousContentCreator.h"
-#include "nsSVGMatrix.h"
 #include "nsIDOMSVGUseElement.h"
 #include "nsIDOMSVGTransformable.h"
 #include "nsSVGElement.h"
 #include "nsSVGUseElement.h"
 #include "gfxMatrix.h"
 
 typedef nsSVGGFrame nsSVGUseFrameBase;
 
--- a/layout/svg/base/src/nsSVGUtils.cpp
+++ b/layout/svg/base/src/nsSVGUtils.cpp
@@ -431,134 +431,121 @@ nsSVGUtils::CoordToFloat(nsPresContext *
       nsSVGSVGElement* ctx = aContent->GetCtx();
       return ctx ? aCoord.GetPercentValue() * ctx->GetLength(nsSVGUtils::XY) : 0.0f;
     }
   default:
     return 0.0f;
   }
 }
 
-nsresult
-nsSVGUtils::GetNearestViewportElement(nsIContent *aContent,
-                                      nsIDOMSVGElement * *aNearestViewportElement)
+PRBool
+nsSVGUtils::EstablishesViewport(nsIContent *aContent)
+{
+  return aContent && aContent->GetNameSpaceID() == kNameSpaceID_SVG &&
+           (aContent->Tag() == nsGkAtoms::svg ||
+            aContent->Tag() == nsGkAtoms::image ||
+            aContent->Tag() == nsGkAtoms::foreignObject ||
+            aContent->Tag() == nsGkAtoms::symbol);
+}
+
+already_AddRefed<nsIDOMSVGElement>
+nsSVGUtils::GetNearestViewportElement(nsIContent *aContent)
 {
-  *aNearestViewportElement = nsnull;
+  nsIContent *element = GetParentElement(aContent);
 
+  while (element && element->GetNameSpaceID() == kNameSpaceID_SVG) {
+    if (EstablishesViewport(element)) {
+      if (element->Tag() == nsGkAtoms::foreignObject) {
+        return nsnull;
+      }
+      return nsCOMPtr<nsIDOMSVGElement>(do_QueryInterface(element)).forget();
+    }
+    element = GetParentElement(element);
+  }
+  return nsnull;
+}
+
+already_AddRefed<nsIDOMSVGElement>
+nsSVGUtils::GetFarthestViewportElement(nsIContent *aContent)
+{
+  nsIContent *element = nsnull;
   nsIContent *ancestor = GetParentElement(aContent);
 
   while (ancestor && ancestor->GetNameSpaceID() == kNameSpaceID_SVG &&
-         ancestor->Tag() != nsGkAtoms::foreignObject) {
-
-    nsCOMPtr<nsIDOMSVGFitToViewBox> fitToViewBox = do_QueryInterface(ancestor);
+                     ancestor->Tag() != nsGkAtoms::foreignObject) {
+    element = ancestor;
+    ancestor = GetParentElement(element);
+  }
 
-    if (fitToViewBox) {
-      // right interface
-      nsCOMPtr<nsIDOMSVGElement> element = do_QueryInterface(ancestor);
-      element.swap(*aNearestViewportElement);
-      return NS_OK;
-    }
-
-    ancestor = GetParentElement(ancestor);
+  if (element && element->Tag() == nsGkAtoms::svg) {
+    return nsCOMPtr<nsIDOMSVGElement>(do_QueryInterface(element)).forget();
   }
-  if (ancestor && ancestor->GetNameSpaceID() == kNameSpaceID_SVG &&
-                  ancestor->Tag() == nsGkAtoms::foreignObject )
-    return NS_ERROR_FAILURE;
-
-  return NS_OK;
+  return nsnull;
 }
 
-nsresult
-nsSVGUtils::AppendTransformUptoElement(nsIContent *aContent, nsIDOMSVGElement *aElement, nsIDOMSVGMatrix * *aCTM){
-  nsresult rv;
-  nsCOMPtr<nsIDOMSVGElement> element = do_QueryInterface(aContent);
-  nsIContent *ancestor = GetParentElement(aContent);
-  if (!aElement) {
-    // calculating GetScreenCTM(): traverse upto the root or non-SVG content.
-    if (ancestor && ancestor->GetNameSpaceID() == kNameSpaceID_SVG) {
-      if (ancestor->Tag() == nsGkAtoms::foreignObject && aContent->Tag() != nsGkAtoms::svg)
-        return NS_ERROR_FAILURE;
-      rv = AppendTransformUptoElement(ancestor, aElement, aCTM);
-      if (NS_FAILED(rv)) return rv;
-    }
-  } else if (element != aElement) { // calculating GetCTM(): stop at aElement.
-    NS_ASSERTION(ancestor != nsnull, "ancestor shouldn't be null.");
-    if (!ancestor)
-      return NS_ERROR_FAILURE;
-    rv = AppendTransformUptoElement(ancestor, aElement, aCTM);
-    if (NS_FAILED(rv)) return rv;
-  }
-
-  nsCOMPtr<nsIDOMSVGMatrix> tmp;
-  if (nsCOMPtr<nsIDOMSVGSVGElement>(do_QueryInterface(aContent))) {
-    nsSVGSVGElement *svgElement = static_cast<nsSVGSVGElement*>(aContent);
-    rv = svgElement->AppendTransform(*aCTM, getter_AddRefs(tmp));
-    if (NS_FAILED(rv)) return rv;
-  } else if (nsCOMPtr<nsIDOMSVGTransformable>(do_QueryInterface(aContent))) {
-    nsSVGGraphicElement *graphicElement = static_cast<nsSVGGraphicElement*>(aContent);
-    rv = graphicElement->AppendTransform(*aCTM, getter_AddRefs(tmp));
-    if (NS_FAILED(rv)) return rv;
-  } else {
-    //XXX aContent may be other type of viewport-establising elements
-    //    (e.g. <use> and <symbol>) and handle them?
-  }
-  if (tmp)
-    tmp.swap(*aCTM);
-
-  return NS_OK;
-}
-
-nsresult
-nsSVGUtils::GetCTM(nsIContent *aContent, nsIDOMSVGMatrix * *aCTM)
+gfxMatrix
+nsSVGUtils::GetCTM(nsSVGElement *aElement, PRBool aScreenCTM)
 {
-  nsresult rv;
-  nsIDocument* currentDoc = aContent->GetCurrentDoc();
+  nsIDocument* currentDoc = aElement->GetCurrentDoc();
   if (currentDoc) {
-    // Flush all pending notifications so that our frames are uptodate
+    // Flush all pending notifications so that our frames are up to date
     currentDoc->FlushPendingNotifications(Flush_Layout);
   }
 
-  *aCTM = nsnull;
-  nsCOMPtr<nsIDOMSVGElement> nearestViewportElement;
-  rv = GetNearestViewportElement(aContent, getter_AddRefs(nearestViewportElement));
-  // According to the spec(http://www.w3.org/TR/SVG11/types.html#InterfaceSVGLocatable),
-  // GetCTM is strictly defined to be the CTM for nearestViewportElement,
-  // Thus, if it is null, this is null, too.
-  if (NS_FAILED(rv) || !nearestViewportElement)
-    return NS_OK; // we can't throw exceptions from this API.
-
-  nsCOMPtr<nsIDOMSVGMatrix> tmp;
-  rv = NS_NewSVGMatrix(getter_AddRefs(tmp), 1, 0, 0, 1, 0, 0);
-  if (NS_FAILED(rv)) return NS_OK; // we can't throw exceptions from this API.
-  tmp.swap(*aCTM);
-  rv = AppendTransformUptoElement(aContent, nearestViewportElement, aCTM);
-  if (NS_FAILED(rv))
-    tmp.swap(*aCTM);
-  return NS_OK; // we can't throw exceptions from this API.
-}
+  gfxMatrix matrix = aElement->PrependLocalTransformTo(gfxMatrix());
+  nsSVGElement *element = aElement;
+  nsIContent *ancestor = GetParentElement(aElement);
 
-nsresult
-nsSVGUtils::GetScreenCTM(nsIContent *aContent, nsIDOMSVGMatrix * *aCTM)
-{
-  nsresult rv;
-  nsIDocument* currentDoc = aContent->GetCurrentDoc();
-  if (currentDoc) {
-    // Flush all pending notifications so that our frames are uptodate
-    currentDoc->FlushPendingNotifications(Flush_Layout);
+  while (ancestor && ancestor->GetNameSpaceID() == kNameSpaceID_SVG &&
+                     ancestor->Tag() != nsGkAtoms::foreignObject) {
+    element = static_cast<nsSVGElement*>(ancestor);
+    matrix *= element->PrependLocalTransformTo(gfxMatrix()); // i.e. *A*ppend
+    if (!aScreenCTM && EstablishesViewport(element)) {
+      if (!element->NodeInfo()->Equals(nsGkAtoms::svg, kNameSpaceID_SVG) &&
+          !element->NodeInfo()->Equals(nsGkAtoms::symbol, kNameSpaceID_SVG)) {
+        NS_ERROR("New (SVG > 1.1) SVG viewport establishing element?");
+        return gfxMatrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); // singular
+      }
+      // XXX spec seems to say x,y translation should be undone for IsInnerSVG
+      return matrix;
+    }
+    ancestor = GetParentElement(element);      
+  }
+  if (!aScreenCTM) {
+    // didn't find a nearestViewportElement
+    return gfxMatrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); // singular
+  }
+  if (!ancestor || !ancestor->IsNodeOfType(nsINode::eELEMENT)) {
+    return matrix;
   }
-
-  *aCTM = nsnull;
-
-  nsCOMPtr<nsIDOMSVGMatrix> tmp;
-  rv = NS_NewSVGMatrix(getter_AddRefs(tmp), 1, 0, 0, 1, 0, 0);
-  if (NS_FAILED(rv)) return NS_OK; // we can't throw exceptions from this API.
-  tmp.swap(*aCTM);
-  rv = AppendTransformUptoElement(aContent, nsnull, aCTM);
-  if (NS_FAILED(rv))
-    tmp.swap(*aCTM);
-  return NS_OK; // we can't throw exceptions from this API.
+  if (ancestor->GetNameSpaceID() == kNameSpaceID_SVG) {
+    if (element->Tag() != nsGkAtoms::svg) {
+      return gfxMatrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); // singular
+    }
+    return matrix * GetCTM(static_cast<nsSVGElement*>(ancestor), PR_TRUE);
+  }
+  // XXX this does not take into account CSS transform, or that the non-SVG
+  // content that we've hit may itself be inside an SVG foreignObject higher up
+  float x = 0.0f, y = 0.0f;
+  if (element->NodeInfo()->Equals(nsGkAtoms::svg, kNameSpaceID_SVG)) {
+    nsIPresShell *presShell = currentDoc->GetPrimaryShell();
+    if (element && presShell) {
+      nsPresContext *context = presShell->GetPresContext();
+      if (context) {
+        nsIFrame* frame = presShell->GetPrimaryFrameFor(element);
+        nsIFrame* ancestorFrame = presShell->GetRootFrame();
+        if (frame && ancestorFrame) {
+          nsPoint point = frame->GetOffsetTo(ancestorFrame);
+          x = nsPresContext::AppUnitsToFloatCSSPixels(point.x);
+          y = nsPresContext::AppUnitsToFloatCSSPixels(point.y);
+        }
+      }
+    }
+  }
+  return matrix * gfxMatrix().Translate(gfxPoint(x, y));
 }
 
 nsSVGDisplayContainerFrame*
 nsSVGUtils::GetNearestSVGViewport(nsIFrame *aFrame)
 {
   NS_ASSERTION(aFrame->IsFrameOfType(nsIFrame::eSVG), "SVG frame expected");
   if (aFrame->GetType() == nsGkAtoms::svgOuterSVGFrame) {
     return nsnull;
@@ -569,43 +556,16 @@ nsSVGUtils::GetNearestSVGViewport(nsIFra
         aFrame->GetType() == nsGkAtoms::svgOuterSVGFrame) {
       return do_QueryFrame(aFrame);
     }
   }
   NS_NOTREACHED("This is not reached. It's only needed to compile.");
   return nsnull;
 }
 
-nsresult
-nsSVGUtils::GetFarthestViewportElement(nsIContent *aContent,
-                                       nsIDOMSVGElement * *aFarthestViewportElement)
-{
-  *aFarthestViewportElement = nsnull;
-
-  nsIContent *ancestor = GetParentElement(aContent);
-  nsCOMPtr<nsIDOMSVGElement> element;
-
-  while (ancestor && ancestor->GetNameSpaceID() == kNameSpaceID_SVG &&
-         ancestor->Tag() != nsGkAtoms::foreignObject) {
-
-    nsCOMPtr<nsIDOMSVGFitToViewBox> fitToViewBox = do_QueryInterface(ancestor);
-
-    if (fitToViewBox) {
-      // right interface
-      element = do_QueryInterface(ancestor);
-    }
-
-    ancestor = GetParentElement(ancestor);
-  }
-
-  element.swap(*aFarthestViewportElement);
-
-  return NS_OK;
-}
-
 nsRect
 nsSVGUtils::FindFilterInvalidation(nsIFrame *aFrame, const nsRect& aRect)
 {
   PRInt32 appUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel();
   nsIntRect rect = aRect.ToOutsidePixels(appUnitsPerDevPixel);
 
   while (aFrame) {
     if (aFrame->GetStateBits() & NS_STATE_IS_OUTER_SVG)
@@ -800,17 +760,17 @@ nsSVGUtils::GetOuterSVGFrameAndCoveredRe
 {
   nsISVGChildFrame* svg = do_QueryFrame(aFrame);
   if (!svg)
     return nsnull;
   *aRect = svg->GetCoveredRegion();
   return GetOuterSVGFrame(aFrame);
 }
 
-already_AddRefed<nsIDOMSVGMatrix>
+gfxMatrix
 nsSVGUtils::GetViewBoxTransform(float aViewportWidth, float aViewportHeight,
                                 float aViewboxX, float aViewboxY,
                                 float aViewboxWidth, float aViewboxHeight,
                                 const nsSVGPreserveAspectRatio &aPreserveAspectRatio,
                                 PRBool aIgnoreAlign)
 {
   NS_ASSERTION(aViewboxWidth > 0, "viewBox width must be greater than zero!");
   NS_ASSERTION(aViewboxHeight > 0, "viewBox height must be greater than zero!");
@@ -886,29 +846,26 @@ nsSVGUtils::GetViewBoxTransform(float aV
       }
     }
     else NS_NOTREACHED("Unknown value for meetOrSlice");
   }
   
   if (aViewboxX) e += -a * aViewboxX;
   if (aViewboxY) f += -d * aViewboxY;
   
-  nsIDOMSVGMatrix *retval;
-  NS_NewSVGMatrix(&retval, a, 0.0f, 0.0f, d, e, f);
-  return retval;
+  return gfxMatrix(a, 0.0f, 0.0f, d, e, f);
 }
 
 gfxMatrix
 nsSVGUtils::GetCanvasTM(nsIFrame *aFrame)
 {
   // XXX yuck, we really need a common interface for GetCanvasTM
 
   if (!aFrame->IsFrameOfType(nsIFrame::eSVG)) {
-    nsCOMPtr<nsIDOMSVGMatrix> matrix = nsSVGIntegrationUtils::GetInitialMatrix(aFrame);
-    return ConvertSVGMatrixToThebes(matrix);
+    return nsSVGIntegrationUtils::GetInitialMatrix(aFrame);
   }
 
   nsIAtom* type = aFrame->GetType();
   if (type == nsGkAtoms::svgForeignObjectFrame) {
     return static_cast<nsSVGForeignObjectFrame*>(aFrame)->GetCanvasTM();
   }
 
   nsSVGContainerFrame *containerFrame = do_QueryFrame(aFrame);
@@ -1033,18 +990,19 @@ nsSVGUtils::PaintFrameWithEffects(nsSVGR
 
   PRBool isTrivialClip = clipPathFrame ? clipPathFrame->IsTrivial() : PR_TRUE;
 
   if (!isOK) {
     // Some resource is missing. We shouldn't paint anything.
     return;
   }
   
-  nsCOMPtr<nsIDOMSVGMatrix> matrix =
-    (clipPathFrame || maskFrame) ? NS_NewSVGMatrix(GetCanvasTM(aFrame)) : nsnull;
+  gfxMatrix matrix;
+  if (clipPathFrame || maskFrame)
+    matrix = GetCanvasTM(aFrame);
 
   /* Check if we need to do additional operations on this child's
    * rendering, which necessitates rendering into another surface. */
   if (opacity != 1.0f || maskFrame || (clipPathFrame && !isTrivialClip)) {
     complexEffects = PR_TRUE;
     gfx->Save();
     gfx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
   }
@@ -1117,18 +1075,17 @@ nsSVGUtils::HitTestClip(nsIFrame *aFrame
 
   nsSVGClipPathFrame *clipPathFrame = props.GetClipPathFrame(nsnull);
   if (!clipPathFrame) {
     // clipPath is not a valid resource, so nothing gets painted, so
     // hit-testing must fail.
     return PR_FALSE;
   }
 
-  nsCOMPtr<nsIDOMSVGMatrix> matrix = NS_NewSVGMatrix(GetCanvasTM(aFrame));
-  return clipPathFrame->ClipHitTest(aFrame, matrix, aPoint);
+  return clipPathFrame->ClipHitTest(aFrame, GetCanvasTM(aFrame), aPoint);
 }
 
 nsIFrame *
 nsSVGUtils::HitTestChildren(nsIFrame *aFrame, const nsPoint &aPoint)
 {
   // XXX: The frame's children are linked in a singly-linked list in document
   // order. If we were to hit test the children in this order we would need to
   // hit test *every* SVG frame, since even if we get a hit, later SVG frames
@@ -1269,35 +1226,29 @@ nsSVGUtils::ConvertSVGMatrixToThebes(nsI
   aMatrix->GetC(&C);
   aMatrix->GetD(&D);
   aMatrix->GetE(&E);
   aMatrix->GetF(&F);
   return gfxMatrix(A, B, C, D, E, F);
 }
 
 PRBool
-nsSVGUtils::HitTestRect(nsIDOMSVGMatrix *aMatrix,
+nsSVGUtils::HitTestRect(const gfxMatrix &aMatrix,
                         float aRX, float aRY, float aRWidth, float aRHeight,
                         float aX, float aY)
 {
-  PRBool result = PR_TRUE;
-
-  if (aMatrix) {
-    gfxContext ctx(GetThebesComputationalSurface());
-    ctx.SetMatrix(ConvertSVGMatrixToThebes(aMatrix));
-
-    ctx.NewPath();
-    ctx.Rectangle(gfxRect(aRX, aRY, aRWidth, aRHeight));
-    ctx.IdentityMatrix();
-
-    if (!ctx.PointInFill(gfxPoint(aX, aY)))
-      result = PR_FALSE;
+  if (aMatrix.IsSingular()) {
+    return PR_FALSE;
   }
-
-  return result;
+  gfxContext ctx(GetThebesComputationalSurface());
+  ctx.SetMatrix(aMatrix);
+  ctx.NewPath();
+  ctx.Rectangle(gfxRect(aRX, aRY, aRWidth, aRHeight));
+  ctx.IdentityMatrix();
+  return ctx.PointInFill(gfxPoint(aX, aY));
 }
 
 gfxRect
 nsSVGUtils::GetClipRectForFrame(nsIFrame *aFrame,
                                 float aX, float aY, float aWidth, float aHeight)
 {
   const nsStyleDisplay* disp = aFrame->GetStyleDisplay();
 
@@ -1334,50 +1285,41 @@ nsSVGUtils::GetClipRectForFrame(nsIFrame
     return clipRect;
   }
   return gfxRect(aX, aY, aWidth, aHeight);
 }
 
 void
 nsSVGUtils::CompositeSurfaceMatrix(gfxContext *aContext,
                                    gfxASurface *aSurface,
-                                   nsIDOMSVGMatrix *aCTM, float aOpacity)
+                                   const gfxMatrix &aCTM, float aOpacity)
 {
-  gfxMatrix matrix = ConvertSVGMatrixToThebes(aCTM);
-  if (matrix.IsSingular())
+  if (aCTM.IsSingular())
     return;
 
   aContext->Save();
-
-  aContext->Multiply(matrix);
-
+  aContext->Multiply(aCTM);
   aContext->SetSource(aSurface);
   aContext->Paint(aOpacity);
-
   aContext->Restore();
 }
 
 void
 nsSVGUtils::CompositePatternMatrix(gfxContext *aContext,
                                    gfxPattern *aPattern,
-                                   nsIDOMSVGMatrix *aCTM, float aWidth, float aHeight, float aOpacity)
+                                   const gfxMatrix &aCTM, float aWidth, float aHeight, float aOpacity)
 {
-  gfxMatrix matrix = ConvertSVGMatrixToThebes(aCTM);
-  if (matrix.IsSingular())
+  if (aCTM.IsSingular())
     return;
 
   aContext->Save();
-
-  SetClipRect(aContext, ConvertSVGMatrixToThebes(aCTM), gfxRect(0, 0, aWidth, aHeight));
-
-  aContext->Multiply(matrix);
-
+  SetClipRect(aContext, aCTM, gfxRect(0, 0, aWidth, aHeight));
+  aContext->Multiply(aCTM);
   aContext->SetPattern(aPattern);
   aContext->Paint(aOpacity);
-
   aContext->Restore();
 }
 
 void
 nsSVGUtils::SetClipRect(gfxContext *aContext,
                         const gfxMatrix &aCTM,
                         const gfxRect &aRect)
 {
@@ -1456,50 +1398,44 @@ nsSVGUtils::CanOptimizeOpacity(nsIFrame 
           style->mStroke.mType == eStyleSVGPaintType_None)
         return PR_TRUE;
     }
   }
   return PR_FALSE;
 }
 
 float
-nsSVGUtils::MaxExpansion(nsIDOMSVGMatrix *aMatrix)
+nsSVGUtils::MaxExpansion(const gfxMatrix &aMatrix)
 {
-  float a, b, c, d;
-  aMatrix->GetA(&a);
-  aMatrix->GetB(&b);
-  aMatrix->GetC(&c);
-  aMatrix->GetD(&d);
-
   // maximum expansion derivation from
   // http://lists.cairographics.org/archives/cairo/2004-October/001980.html
-  float f = (a * a + b * b + c * c + d * d) / 2;
-  float g = (a * a + b * b - c * c - d * d) / 2;
-  float h = a * c + b * d;
+  // and also implemented in cairo_matrix_transformed_circle_major_axis
+  double a = aMatrix.xx;
+  double b = aMatrix.yx;
+  double c = aMatrix.xy;
+  double d = aMatrix.yy;
+  double f = (a * a + b * b + c * c + d * d) / 2;
+  double g = (a * a + b * b - c * c - d * d) / 2;
+  double h = a * c + b * d;
   return sqrt(f + sqrt(g * g + h * h));
 }
 
-already_AddRefed<nsIDOMSVGMatrix>
-nsSVGUtils::AdjustMatrixForUnits(nsIDOMSVGMatrix *aMatrix,
+gfxMatrix
+nsSVGUtils::AdjustMatrixForUnits(const gfxMatrix &aMatrix,
                                  nsSVGEnum *aUnits,
                                  nsIFrame *aFrame)
 {
-  nsCOMPtr<nsIDOMSVGMatrix> fini = aMatrix;
-
   if (aFrame &&
       aUnits->GetAnimValue() == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
     gfxRect bbox = GetBBox(aFrame);
-    nsCOMPtr<nsIDOMSVGMatrix> tmp;
-    aMatrix->Translate(bbox.X(), bbox.Y(), getter_AddRefs(tmp));
-    tmp->ScaleNonUniform(bbox.Width(), bbox.Height(), getter_AddRefs(fini));
+    return gfxMatrix().Scale(bbox.Width(), bbox.Height()) *
+           gfxMatrix().Translate(gfxPoint(bbox.X(), bbox.Y())) *
+           aMatrix;
   }
-
-  nsIDOMSVGMatrix* retval = fini.get();
-  NS_IF_ADDREF(retval);
-  return retval;
+  return aMatrix;
 }
 
 nsIFrame*
 nsSVGUtils::GetFirstNonAAncestorFrame(nsIFrame* aStartFrame)
 {
   for (nsIFrame *ancestorFrame = aStartFrame; ancestorFrame;
        ancestorFrame = ancestorFrame->GetParent()) {
     if (ancestorFrame->GetType() != nsGkAtoms::svgAFrame) {
@@ -1562,16 +1498,27 @@ nsSVGUtils::PathExtentsToMaxStrokeExtent
   double dx = style_expansion * (fabs(ctm.xx) + fabs(ctm.xy));
   double dy = style_expansion * (fabs(ctm.yy) + fabs(ctm.yx));
 
   gfxRect strokeExtents = aPathExtents;
   strokeExtents.Outset(dy, dx, dy, dx);
   return strokeExtents;
 }
 
+/* static */ PRBool
+nsSVGUtils::IsInnerSVG(nsIContent* aContent)
+{
+  if (!aContent->NodeInfo()->Equals(nsGkAtoms::svg, kNameSpaceID_SVG)) {
+    return PR_FALSE;
+  }
+  nsIContent *ancestor = GetParentElement(aContent);
+  return ancestor && ancestor->GetNameSpaceID() == kNameSpaceID_SVG &&
+                     ancestor->Tag() != nsGkAtoms::foreignObject;
+}
+
 // ----------------------------------------------------------------------
 
 nsSVGRenderState::nsSVGRenderState(nsIRenderingContext *aContext) :
   mRenderMode(NORMAL), mRenderingContext(aContext)
 {
   mGfxContext = aContext->ThebesContext();
 }
 
--- a/layout/svg/base/src/nsSVGUtils.h
+++ b/layout/svg/base/src/nsSVGUtils.h
@@ -43,27 +43,27 @@
 
 #include "nscore.h"
 #include "nsCOMPtr.h"
 #include "nsRect.h"
 #include "gfxContext.h"
 #include "nsIRenderingContext.h"
 #include "gfxRect.h"
 #include "gfxMatrix.h"
+#include "nsSVGMatrix.h"
 
 class nsIDocument;
 class nsPresContext;
 class nsIContent;
 class nsStyleCoord;
 class nsFrameList;
 class nsIFrame;
 struct nsStyleSVGPaint;
 class nsIDOMSVGElement;
 class nsIDOMSVGLength;
-class nsIDOMSVGMatrix;
 class nsIURI;
 class nsSVGOuterSVGFrame;
 class nsIPresShell;
 class nsSVGPreserveAspectRatio;
 class nsIAtom;
 class nsSVGLength2;
 class nsSVGElement;
 class nsSVGSVGElement;
@@ -246,56 +246,37 @@ public:
    * Converts a nsStyleCoord into a userspace value.  Handles units
    * Factor (straight userspace), Coord (dimensioned), and Percent (of
    * the current SVG viewport)
    */
   static float CoordToFloat(nsPresContext *aPresContext,
                             nsSVGElement *aContent,
                             const nsStyleCoord &aCoord);
 
-  /*
-   * This does the actual job for GetCTM and GetScreenCTM. When called,
-   * this goes up the tree starting from aContent, until reaching to aElement.
-   * When aElement is null, this goes up to the outermost SVG parent. Then,
-   * this post-multiplies aCTM by each parent node's transformation matrix,
-   * going down the tree from aElement to aContent.
-   * This doesn't initialize aCTM. So callers usually should pass
-   * the identity matrix by aCTM.
+  static gfxMatrix GetCTM(nsSVGElement *aElement, PRBool aScreenCTM);
+
+  /**
+   * Check if this is one of the SVG elements that SVG 1.1 Full says
+   * establishes a viewport: svg, symbol, image or foreignObject.
    */
-  static nsresult AppendTransformUptoElement(nsIContent *aContent,
-                                             nsIDOMSVGElement *aElement,
-                                             nsIDOMSVGMatrix * *aCTM);
-  /*
-   * Return the CTM
-   */
-  static nsresult GetCTM(nsIContent *aContent, nsIDOMSVGMatrix * *aCTM);
+  static PRBool EstablishesViewport(nsIContent *aContent);
 
-  /*
-   * Return the screen CTM
-   */
-  static nsresult GetScreenCTM(nsIContent *aContent, nsIDOMSVGMatrix * *aCTM);
-  /*
-   * Return the nearest viewport element
-   */
-  static nsresult GetNearestViewportElement(nsIContent *aContent,
-                                            nsIDOMSVGElement * *aNearestViewportElement);
+  static already_AddRefed<nsIDOMSVGElement>
+  GetNearestViewportElement(nsIContent *aContent);
+
+  static already_AddRefed<nsIDOMSVGElement>
+  GetFarthestViewportElement(nsIContent *aContent);
 
   /**
    * Gets the nearest nsSVGInnerSVGFrame or nsSVGOuterSVGFrame frame. aFrame
    * must be an SVG frame. If aFrame is of type nsGkAtoms::svgOuterSVGFrame,
    * returns nsnull.
    */
   static nsSVGDisplayContainerFrame* GetNearestSVGViewport(nsIFrame *aFrame);
-
-  /*
-   * Get the farthest viewport element
-   */
-  static nsresult GetFarthestViewportElement(nsIContent *aContent,
-                                             nsIDOMSVGElement * *aFarthestViewportElement);
-
+  
   /**
    * Figures out the worst case invalidation area for a frame, taking
    * filters into account.
    * Note that the caller is responsible for making sure that any cached
    * covered regions in the frame tree rooted at aFrame are up to date.
    * @param aRect the area in app units that needs to be invalidated in aFrame
    * @return the rect in app units that should be invalidated, taking
    * filters into account. Will return aRect when no filters are present.
@@ -356,17 +337,17 @@ public:
    * @param aRect gets a rectangle in app units
    * @return the outer SVG frame which aRect is relative to
    */
   static nsIFrame*
   GetOuterSVGFrameAndCoveredRegion(nsIFrame* aFrame, nsRect* aRect);
 
   /* Generate a viewbox to viewport tranformation matrix */
   
-  static already_AddRefed<nsIDOMSVGMatrix>
+  static gfxMatrix
   GetViewBoxTransform(float aViewportWidth, float aViewportHeight,
                       float aViewboxX, float aViewboxY,
                       float aViewboxWidth, float aViewboxHeight,
                       const nsSVGPreserveAspectRatio &aPreserveAspectRatio,
                       PRBool aIgnoreAlign = PR_FALSE);
 
   /* Paint SVG frame with SVG effects - aDirtyRect is the area being
    * redrawn, in device pixel coordinates relative to the outer svg */
@@ -436,17 +417,17 @@ public:
    */
   static gfxMatrix
   ConvertSVGMatrixToThebes(nsIDOMSVGMatrix *aMatrix);
 
   /*
    * Hit test a given rectangle/matrix.
    */
   static PRBool
-  HitTestRect(nsIDOMSVGMatrix *aMatrix,
+  HitTestRect(const gfxMatrix &aMatrix,
               float aRX, float aRY, float aRWidth, float aRHeight,
               float aX, float aY);
 
 
   /**
    * Get the clip rect for the given frame, taking into account the CSS 'clip'
    * property. See:
    * http://www.w3.org/TR/SVG11/masking.html#OverflowAndClipProperties
@@ -454,21 +435,21 @@ public:
    * the viewport established by aFrame.
    */
   static gfxRect
   GetClipRectForFrame(nsIFrame *aFrame,
                       float aX, float aY, float aWidth, float aHeight);
 
   static void CompositeSurfaceMatrix(gfxContext *aContext,
                                      gfxASurface *aSurface,
-                                     nsIDOMSVGMatrix *aCTM, float aOpacity);
+                                     const gfxMatrix &aCTM, float aOpacity);
 
   static void CompositePatternMatrix(gfxContext *aContext,
                                      gfxPattern *aPattern,
-                                     nsIDOMSVGMatrix *aCTM, float aWidth, float aHeight, float aOpacity);
+                                     const gfxMatrix &aCTM, float aWidth, float aHeight, float aOpacity);
 
   static void SetClipRect(gfxContext *aContext,
                           const gfxMatrix &aCTM,
                           const gfxRect &aRect);
 
   /**
    * If aIn can be represented exactly using an nsIntRect (i.e. integer-aligned edges and
    * coordinates in the PRInt32 range) then we set aOut to that rectangle, otherwise
@@ -486,28 +467,28 @@ public:
    * not applying filters and not both stroking and filling, we can
    * generate the same result without going through the overhead of a
    * push/pop group. */
   static PRBool
   CanOptimizeOpacity(nsIFrame *aFrame);
 
   /* Calculate the maximum expansion of a matrix */
   static float
-  MaxExpansion(nsIDOMSVGMatrix *aMatrix);
+  MaxExpansion(const gfxMatrix &aMatrix);
 
   /**
    * Take the CTM to userspace for an element, and adjust it to a CTM to its
    * object bounding box space if aUnits is SVG_UNIT_TYPE_OBJECTBOUNDINGBOX.
    * (I.e. so that [0,0] is at the top left of its bbox, and [1,1] is at the
    * bottom right of its bbox).
    *
    * If the bbox is empty, this will return a singular matrix.
    */
-  static already_AddRefed<nsIDOMSVGMatrix>
-  AdjustMatrixForUnits(nsIDOMSVGMatrix *aMatrix,
+  static gfxMatrix
+  AdjustMatrixForUnits(const gfxMatrix &aMatrix,
                        nsSVGEnum *aUnits,
                        nsIFrame *aFrame);
 
   /**
    * Get bounding-box for aFrame. Matrix propagation is disabled so the
    * bounding box is computed in terms of aFrame's own user space.
    */
   static gfxRect GetBBox(nsIFrame *aFrame);
@@ -546,14 +527,20 @@ public:
    * the fact that cairo does have an API for getting the tight device space
    * fill/path extents.
    *
    * This should die once bug 478152 is fixed.
    */
   static gfxRect PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents,
                                                nsSVGGeometryFrame* aFrame);
 
+  /**
+   * Returns true if aContent is an SVG <svg> element that is the child of
+   * another non-foreignObject SVG element.
+   */
+  static PRBool IsInnerSVG(nsIContent* aContent);
+    
 private:
   /* Computational (nil) surfaces */
   static gfxASurface *mThebesComputationalSurface;
 };
 
 #endif