Part 20 - Add more gfx3DMatrix transformation function and use these in nsStyleTransformMatrix. r=derf
authorMatt Woodrow <mwoodrow@mozilla.com>
Tue, 27 Sep 2011 10:54:45 +1300
changeset 77612 24fa4e8bed1a0741ad2c5b36cdef6f77ae1bea4b
parent 77611 f1af522b8b471fb22e3d9808f792d0c7fd8bebfe
child 77613 184cfbecb1c322217e07fab4cfc0efffdfb93d6f
push id2169
push usermwoodrow@mozilla.com
push dateMon, 26 Sep 2011 21:59:18 +0000
treeherdermozilla-inbound@24fa4e8bed1a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersderf
milestone9.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Part 20 - Add more gfx3DMatrix transformation function and use these in nsStyleTransformMatrix. r=derf
gfx/thebes/gfx3DMatrix.cpp
gfx/thebes/gfx3DMatrix.h
layout/style/nsStyleTransformMatrix.cpp
layout/style/nsStyleTransformMatrix.h
--- a/gfx/thebes/gfx3DMatrix.cpp
+++ b/gfx/thebes/gfx3DMatrix.cpp
@@ -37,16 +37,50 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "gfxMatrix.h"
 #include "gfx3DMatrix.h"
 #include <math.h>
 #include <algorithm>
 using namespace std;
 
+/* Force small values to zero.  We do this to avoid having sin(360deg)
+ * evaluate to a tiny but nonzero value.
+ */
+static double FlushToZero(double aVal)
+{
+  if (-FLT_EPSILON < aVal && aVal < FLT_EPSILON)
+    return 0.0f;
+  else
+    return aVal;
+}
+
+/* Computes tan(aTheta).  For values of aTheta such that tan(aTheta) is
+ * undefined or very large, SafeTangent returns a manageably large value
+ * of the correct sign.
+ */
+static double SafeTangent(double aTheta)
+{
+  const double kEpsilon = 0.0001;
+
+  /* tan(theta) = sin(theta)/cos(theta); problems arise when
+   * cos(theta) is too close to zero.  Limit cos(theta) to the
+   * range [-1, -epsilon] U [epsilon, 1].
+   */
+  double sinTheta = sin(aTheta);
+  double cosTheta = cos(aTheta);
+
+  if (cosTheta >= 0 && cosTheta < kEpsilon)
+    cosTheta = kEpsilon;
+  else if (cosTheta < 0 && cosTheta >= -kEpsilon)
+    cosTheta = -kEpsilon;
+
+  return FlushToZero(sinTheta / cosTheta);
+}
+
 gfx3DMatrix::gfx3DMatrix(void)
 {
   _11 = _22 = _33 = _44 = 1.0f;
   _12 = _13 = _14 = 0.0f;
   _21 = _23 = _24 = 0.0f;
   _31 = _32 = _34 = 0.0f;
   _41 = _42 = _43 = 0.0f;
 }
@@ -177,41 +211,179 @@ gfx3DMatrix::TranslatePost(const gfxPoin
     _42 += _44 * aPoint.y;
     _13 += _14 * aPoint.z;
     _23 += _24 * aPoint.z;
     _33 += _34 * aPoint.z;
     _43 += _44 * aPoint.z;
 }
 
 void
-gfx3DMatrix::SkewXY(float aSkew)
+gfx3DMatrix::SkewXY(double aSkew)
 {
     (*this)[1] += (*this)[0] * aSkew;
 }
 
 void 
-gfx3DMatrix::SkewXZ(float aSkew)
+gfx3DMatrix::SkewXZ(double aSkew)
 {
     (*this)[2] += (*this)[0] * aSkew;
 }
 
 void
-gfx3DMatrix::SkewYZ(float aSkew)
+gfx3DMatrix::SkewYZ(double aSkew)
 {
     (*this)[2] += (*this)[1] * aSkew;
 }
 
 void
 gfx3DMatrix::Scale(float aX, float aY, float aZ)
 {
     (*this)[0] *= aX;
     (*this)[1] *= aY;
     (*this)[2] *= aZ;
 }
 
+void
+gfx3DMatrix::Perspective(float aDepth)
+{
+  NS_ASSERTION(aDepth > 0.0f, "Perspective must be positive!");
+  _31 += -1.0/aDepth * _41;
+  _32 += -1.0/aDepth * _42;
+  _33 += -1.0/aDepth * _43;
+  _34 += -1.0/aDepth * _44;
+}
+
+void gfx3DMatrix::SkewXY(double aXSkew, double aYSkew)
+{
+  float tanX = SafeTangent(aXSkew);
+  float tanY = SafeTangent(aYSkew);
+  float temp;
+
+  temp = _11;
+  _11 += tanY * _21;
+  _21 += tanX * temp;
+
+  temp = _12;
+  _12 += tanY * _22;
+  _22 += tanX * temp;
+  
+  temp = _13;
+  _13 += tanY * _23;
+  _23 += tanX * temp;
+  
+  temp = _14;
+  _14 += tanY * _24;
+  _24 += tanX * temp;
+}
+
+void
+gfx3DMatrix::RotateX(double aTheta)
+{
+  double cosTheta = FlushToZero(cos(aTheta));
+  double sinTheta = FlushToZero(sin(aTheta));
+
+  float temp;
+
+  temp = _21;
+  _21 = cosTheta * _21 + sinTheta * _31;
+  _31 = -sinTheta * temp + cosTheta * _31;
+  
+  temp = _22;
+  _22 = cosTheta * _22 + sinTheta * _32;
+  _32 = -sinTheta * temp + cosTheta * _32;
+  
+  temp = _23;
+  _23 = cosTheta * _23 + sinTheta * _33;
+  _33 = -sinTheta * temp + cosTheta * _33;
+  
+  temp = _24;
+  _24 = cosTheta * _24 + sinTheta * _34;
+  _34 = -sinTheta * temp + cosTheta * _34;
+}
+
+void
+gfx3DMatrix::RotateY(double aTheta)
+{
+  double cosTheta = FlushToZero(cos(aTheta));
+  double sinTheta = FlushToZero(sin(aTheta));
+
+  float temp;
+
+  temp = _11;
+  _11 = cosTheta * _11 + -sinTheta * _31;
+  _31 = sinTheta * temp + cosTheta * _31;
+  
+  temp = _12;
+  _12 = cosTheta * _12 + -sinTheta * _32;
+  _32 = sinTheta * temp + cosTheta * _32;
+  
+  temp = _13;
+  _13 = cosTheta * _13 + -sinTheta * _33;
+  _33 = sinTheta * temp + cosTheta * _33;
+  
+  temp = _14;
+  _14 = cosTheta * _14 + -sinTheta * _34;
+  _34 = sinTheta * temp + cosTheta * _34;
+}
+
+void
+gfx3DMatrix::RotateZ(double aTheta)
+{
+  double cosTheta = FlushToZero(cos(aTheta));
+  double sinTheta = FlushToZero(sin(aTheta));
+
+  float temp;
+
+  temp = _11;
+  _11 = cosTheta * _11 + sinTheta * _21;
+  _21 = -sinTheta * temp + cosTheta * _21;
+  
+  temp = _12;
+  _12 = cosTheta * _12 + sinTheta * _22;
+  _22 = -sinTheta * temp + cosTheta * _22;
+  
+  temp = _13;
+  _13 = cosTheta * _13 + sinTheta * _23;
+  _23 = -sinTheta * temp + cosTheta * _23;
+  
+  temp = _14;
+  _14 = cosTheta * _14 + sinTheta * _24;
+  _24 = -sinTheta * temp + cosTheta * _24;
+}
+
+void 
+gfx3DMatrix::PreMultiply(const gfx3DMatrix& aOther)
+{
+  *this = aOther * (*this);
+}
+
+void
+gfx3DMatrix::PreMultiply(const gfxMatrix& aOther)
+{
+  gfx3DMatrix temp;
+  temp._11 = aOther.xx * _11 + aOther.yx * _21;
+  temp._21 = aOther.xy * _11 + aOther.yy * _21;
+  temp._31 = _31;
+  temp._41 = aOther.x0 * _11 + aOther.y0 * _21 + _41;
+  temp._12 = aOther.xx * _12 + aOther.yx * _22;
+  temp._22 = aOther.xy * _12 + aOther.yy * _22;
+  temp._32 = _32;
+  temp._42 = aOther.x0 * _12 + aOther.y0 * _22 + _42;
+  temp._13 = aOther.xx * _13 + aOther.yx * _23;
+  temp._23 = aOther.xy * _13 + aOther.yy * _23;
+  temp._33 = _33;
+  temp._43 = aOther.x0 * _13 + aOther.y0 * _23 + _43;
+  temp._14 = aOther.xx * _14 + aOther.yx * _24;
+  temp._24 = aOther.xy * _14 + aOther.yy * _24;
+  temp._34 = _34;
+  temp._44 = aOther.x0 * _14 + aOther.y0 * _24 + _44;
+
+  *this = temp;
+}
+
 gfx3DMatrix
 gfx3DMatrix::Translation(float aX, float aY, float aZ)
 {
   gfx3DMatrix matrix;
 
   matrix._41 = aX;
   matrix._42 = aY;
   matrix._43 = aZ;
--- a/gfx/thebes/gfx3DMatrix.h
+++ b/gfx/thebes/gfx3DMatrix.h
@@ -122,35 +122,126 @@ public:
 
   /**
    * Returns true if the matrix is the identity matrix. The most important
    * property we require is that gfx3DMatrix().IsIdentity() returns true.
    */
   PRBool IsIdentity() const;
 
   /**
+   * Pre-multiplication transformation functions:
+   *
+   * These functions construct a temporary matrix containing
+   * a single transformation and pre-multiply it onto the current
+   * matrix.
+   */
+
+  /**
    * Add a translation by aPoint to the matrix.
-   * This is functionally equivalent to:
-   * gfx3DMatrix::Translation(aPoint) * matrix
+   *
+   * This creates this temporary matrix:
+   * |  1        0        0         0 |
+   * |  0        1        0         0 |
+   * |  0        0        1         0 |
+   * |  aPoint.x aPoint.y aPoint.z  1 |
    */
   void Translate(const gfxPoint3D& aPoint);
 
+  /** 
+   * Skew the matrix.
+   *
+   * This creates this temporary matrix:
+   * | 1           tan(aYSkew) 0 0 |
+   * | tan(aXSkew) 1           0 0 |
+   * | 0           0           1 0 |
+   * | 0           0           0 1 |
+   */
+  void SkewXY(double aXSkew, double aYSkew);
+  
+  void SkewXY(double aSkew);
+  void SkewXZ(double aSkew);
+  void SkewYZ(double aSkew);
+
+  /**
+   * Scale the matrix
+   *
+   * This creates this temporary matrix:
+   * | aX 0  0  0 |
+   * | 0  aY 0  0 |
+   * | 0  0  aZ 0 |
+   * | 0  0  0  1 |
+   */
+  void Scale(float aX, float aY, float aZ);
+
+  /**
+   * Rotate around the X axis..
+   *
+   * This creates this temporary matrix:
+   * | 1 0            0           0 |
+   * | 0 cos(aTheta)  sin(aTheta) 0 |
+   * | 0 -sin(aTheta) cos(aTheta) 0 |
+   * | 0 0            0           1 |
+   */
+  void RotateX(double aTheta);
+  
+  /**
+   * Rotate around the Y axis..
+   *
+   * This creates this temporary matrix:
+   * | cos(aTheta) 0 -sin(aTheta) 0 |
+   * | 0           1 0            0 |
+   * | sin(aTheta) 0 cos(aTheta)  0 |
+   * | 0           0 0            1 |
+   */
+  void RotateY(double aTheta);
+  
+  /**
+   * Rotate around the Z axis..
+   *
+   * This creates this temporary matrix:
+   * | cos(aTheta)  sin(aTheta)  0 0 |
+   * | -sin(aTheta) cos(aTheta)  0 0 |
+   * | 0            0            1 0 |
+   * | 0            0            0 1 |
+   */
+  void RotateZ(double aTheta);
+
+  /**
+   * Apply perspective to the matrix.
+   *
+   * This creates this temporary matrix:
+   * | 1 0 0 0         |
+   * | 0 1 0 0         |
+   * | 0 0 1 -1/aDepth |
+   * | 0 0 0 1         |
+   */
+  void Perspective(float aDepth);
+
+  /**
+   * Pre multiply an existing matrix onto the current
+   * matrix
+   */
+  void PreMultiply(const gfx3DMatrix& aOther);
+  void PreMultiply(const gfxMatrix& aOther);
+
+  /**
+   * Post-multiplication transformation functions:
+   *
+   * These functions construct a temporary matrix containing
+   * a single transformation and post-multiply it onto the current
+   * matrix.
+   */
+  
   /**
    * Add a translation by aPoint after the matrix.
    * This is functionally equivalent to:
-   * matrix *gfx3DMatrix::Translation(aPoint)
+   * matrix * gfx3DMatrix::Translation(aPoint)
    */
   void TranslatePost(const gfxPoint3D& aPoint);
 
-  void SkewXY(float aSkew);
-  void SkewXZ(float aSkew);
-  void SkewYZ(float aSkew);
-
-  void Scale(float aX, float aY, float aZ);
-
   /**
    * Transforms a point according to this matrix.
    */
   gfxPoint Transform(const gfxPoint& point) const;
 
   /**
    * Transforms a rectangle according to this matrix
    */
--- a/layout/style/nsStyleTransformMatrix.cpp
+++ b/layout/style/nsStyleTransformMatrix.cpp
@@ -47,16 +47,18 @@
 #include "nsRuleNode.h"
 #include "nsCSSKeywords.h"
 #include "nsMathUtils.h"
 #include "CSSCalc.h"
 #include "nsStyleAnimation.h"
 
 namespace css = mozilla::css;
 
+namespace nsStyleTransformMatrix {
+
 /* Note on floating point precision: The transform matrix is an array
  * of single precision 'float's, and so are most of the input values
  * we get from the style system, but intermediate calculations
  * involving angles need to be done in 'double'.
  */
 
 /* Force small values to zero.  We do this to avoid having sin(360deg)
  * evaluate to a tiny but nonzero value.
@@ -64,39 +66,16 @@ namespace css = mozilla::css;
 static double FlushToZero(double aVal)
 {
   if (-FLT_EPSILON < aVal && aVal < FLT_EPSILON)
     return 0.0f;
   else
     return aVal;
 }
 
-/* Computes tan(aTheta).  For values of aTheta such that tan(aTheta) is
- * undefined or very large, SafeTangent returns a manageably large value
- * of the correct sign.
- */
-static double SafeTangent(double aTheta)
-{
-  const double kEpsilon = 0.0001;
-
-  /* tan(theta) = sin(theta)/cos(theta); problems arise when
-   * cos(theta) is too close to zero.  Limit cos(theta) to the
-   * range [-1, -epsilon] U [epsilon, 1].
-   */
-  double sinTheta = sin(aTheta);
-  double cosTheta = cos(aTheta);
-
-  if (cosTheta >= 0 && cosTheta < kEpsilon)
-    cosTheta = kEpsilon;
-  else if (cosTheta < 0 && cosTheta >= -kEpsilon)
-    cosTheta = -kEpsilon;
-
-  return FlushToZero(sinTheta / cosTheta);
-}
-
 /* Helper function to fill in an nscoord with the specified nsCSSValue. */
 static nscoord CalcLength(const nsCSSValue &aValue,
                           nsStyleContext* aContext,
                           nsPresContext* aPresContext,
                           PRBool &aCanStoreInRuleTree)
 {
   if (aValue.GetUnit() == eCSSUnit_Pixel ||
       aValue.GetUnit() == eCSSUnit_Number) {
@@ -108,19 +87,18 @@ static nscoord CalcLength(const nsCSSVal
     //
     // Raw numbers are treated as being pixels.
     return nsPresContext::CSSPixelsToAppUnits(aValue.GetFloatValue());
   }
   return nsRuleNode::CalcLength(aValue, aContext, aPresContext,
                                 aCanStoreInRuleTree);
 }
 
-static void
-ProcessTranslatePart(float& aResult,
-                     const nsCSSValue& aValue,
+static float
+ProcessTranslatePart(const nsCSSValue& aValue,
                      nsStyleContext* aContext,
                      nsPresContext* aPresContext,
                      PRBool& aCanStoreInRuleTree,
                      nscoord aSize, float aAppUnitsPerMatrixUnit)
 {
   nscoord offset = 0;
   float percent = 0.0f;
 
@@ -132,61 +110,67 @@ ProcessTranslatePart(float& aResult,
                                               aCanStoreInRuleTree);
     percent = result.mPercent;
     offset = result.mLength;
   } else {
     offset = CalcLength(aValue, aContext, aPresContext,
                          aCanStoreInRuleTree);
   }
 
-  aResult = (percent * NSAppUnitsToFloatPixels(aSize, aAppUnitsPerMatrixUnit)) + 
-            NSAppUnitsToFloatPixels(offset, aAppUnitsPerMatrixUnit);
+  return (percent * NSAppUnitsToFloatPixels(aSize, aAppUnitsPerMatrixUnit)) + 
+         NSAppUnitsToFloatPixels(offset, aAppUnitsPerMatrixUnit);
 }
 
+/**
+ * Helper functions to process all the transformation function types.
+ *
+ * These take a matrix parameter to accumulate the current matrix.
+ */
+
 /* Helper function to process a matrix entry. */
-/* static */ gfx3DMatrix
-nsStyleTransformMatrix::ProcessMatrix(const nsCSSValue::Array* aData,
-                                      nsStyleContext* aContext,
-                                      nsPresContext* aPresContext,
-                                      PRBool& aCanStoreInRuleTree,
-                                      nsRect& aBounds, float aAppUnitsPerMatrixUnit,
-                                      PRBool *aPercentX, PRBool *aPercentY)
+static void
+ProcessMatrix(gfx3DMatrix& aMatrix,
+              const nsCSSValue::Array* aData,
+              nsStyleContext* aContext,
+              nsPresContext* aPresContext,
+              PRBool& aCanStoreInRuleTree,
+              nsRect& aBounds, float aAppUnitsPerMatrixUnit)
 {
   NS_PRECONDITION(aData->Count() == 7, "Invalid array!");
 
-  gfx3DMatrix result;
+  gfxMatrix result;
 
   /* Take the first four elements out of the array as floats and store
    * them.
    */
-  result._11 = aData->Item(1).GetFloatValue();
-  result._12 = aData->Item(2).GetFloatValue();
-  result._21 = aData->Item(3).GetFloatValue();
-  result._22 = aData->Item(4).GetFloatValue();
+  result.xx = aData->Item(1).GetFloatValue();
+  result.yx = aData->Item(2).GetFloatValue();
+  result.xy = aData->Item(3).GetFloatValue();
+  result.yy = aData->Item(4).GetFloatValue();
 
   /* The last two elements have their length parts stored in aDelta
    * and their percent parts stored in aX[0] and aY[1].
    */
-  ProcessTranslatePart(result._41, aData->Item(5),
-                       aContext, aPresContext, aCanStoreInRuleTree,
-                       aBounds.Width(), aAppUnitsPerMatrixUnit);
-  ProcessTranslatePart(result._42, aData->Item(6),
-                       aContext, aPresContext, aCanStoreInRuleTree,
-                       aBounds.Height(), aAppUnitsPerMatrixUnit);
+  result.x0 = ProcessTranslatePart(aData->Item(5),
+                                   aContext, aPresContext, aCanStoreInRuleTree,
+                                   aBounds.Width(), aAppUnitsPerMatrixUnit);
+  result.y0 = ProcessTranslatePart(aData->Item(6),
+                                   aContext, aPresContext, aCanStoreInRuleTree,
+                                   aBounds.Height(), aAppUnitsPerMatrixUnit);
 
-  return result;
+  aMatrix.PreMultiply(result);
 }
 
-/*static */ gfx3DMatrix
-nsStyleTransformMatrix::ProcessMatrix3D(const nsCSSValue::Array* aData,
-                                        nsStyleContext* aContext,
-                                        nsPresContext* aPresContext,
-                                        PRBool& aCanStoreInRuleTree,
-                                        nsRect& aBounds, float aAppUnitsPerMatrixUnit,
-                                        PRBool *aPercentX, PRBool *aPercentY)
+static void 
+ProcessMatrix3D(gfx3DMatrix& aMatrix,
+                const nsCSSValue::Array* aData,
+                nsStyleContext* aContext,
+                nsPresContext* aPresContext,
+                PRBool& aCanStoreInRuleTree,
+                nsRect& aBounds, float aAppUnitsPerMatrixUnit)
 {
   NS_PRECONDITION(aData->Count() == 17, "Invalid array!");
 
   gfx3DMatrix temp;
 
   temp._11 = aData->Item(1).GetFloatValue();
   temp._12 = aData->Item(2).GetFloatValue();
   temp._13 = aData->Item(3).GetFloatValue();
@@ -196,378 +180,293 @@ nsStyleTransformMatrix::ProcessMatrix3D(
   temp._23 = aData->Item(7).GetFloatValue();
   temp._24 = aData->Item(8).GetFloatValue();
   temp._31 = aData->Item(9).GetFloatValue();
   temp._32 = aData->Item(10).GetFloatValue();
   temp._33 = aData->Item(11).GetFloatValue();
   temp._34 = aData->Item(12).GetFloatValue();
   temp._44 = aData->Item(16).GetFloatValue();
 
-  ProcessTranslatePart(temp._41, aData->Item(13),
-                       aContext, aPresContext, aCanStoreInRuleTree,
-                       aBounds.Width(), aAppUnitsPerMatrixUnit);
-  ProcessTranslatePart(temp._42, aData->Item(14),
-                       aContext, aPresContext, aCanStoreInRuleTree,
-                       aBounds.Height(), aAppUnitsPerMatrixUnit);
-  ProcessTranslatePart(temp._43, aData->Item(15),
-                       aContext, aPresContext, aCanStoreInRuleTree,
-                       aBounds.Height(), aAppUnitsPerMatrixUnit);
-  return temp;
+  temp._41 = ProcessTranslatePart(aData->Item(13),
+                                  aContext, aPresContext, aCanStoreInRuleTree,
+                                  aBounds.Width(), aAppUnitsPerMatrixUnit);
+  temp._42 = ProcessTranslatePart(aData->Item(14),
+                                  aContext, aPresContext, aCanStoreInRuleTree,
+                                  aBounds.Height(), aAppUnitsPerMatrixUnit);
+  temp._43 = ProcessTranslatePart(aData->Item(15),
+                                  aContext, aPresContext, aCanStoreInRuleTree,
+                                  aBounds.Height(), aAppUnitsPerMatrixUnit);
+
+  aMatrix.PreMultiply(temp);
 }
 
 /* Helper function to process two matrices that we need to interpolate between */
-/* static */ gfx3DMatrix
-nsStyleTransformMatrix::ProcessInterpolateMatrix(const nsCSSValue::Array* aData,
-                                                 nsStyleContext* aContext,
-                                                 nsPresContext* aPresContext,
-                                                 PRBool& aCanStoreInRuleTree,
-                                                 nsRect& aBounds, float aAppUnitsPerMatrixUnit)
+static void
+ProcessInterpolateMatrix(gfx3DMatrix& aMatrix,
+                         const nsCSSValue::Array* aData,
+                         nsStyleContext* aContext,
+                         nsPresContext* aPresContext,
+                         PRBool& aCanStoreInRuleTree,
+                         nsRect& aBounds, float aAppUnitsPerMatrixUnit)
 {
   NS_PRECONDITION(aData->Count() == 4, "Invalid array!");
 
   gfx3DMatrix matrix1, matrix2;
   if (aData->Item(1).GetUnit() == eCSSUnit_List) {
-    matrix1 = ReadTransforms(aData->Item(1).GetListValue(),
+    matrix1 = nsStyleTransformMatrix::ReadTransforms(aData->Item(1).GetListValue(),
                              aContext, aPresContext,
                              aCanStoreInRuleTree,
                              aBounds, aAppUnitsPerMatrixUnit);
   }
   if (aData->Item(2).GetUnit() == eCSSUnit_List) {
     matrix2 = ReadTransforms(aData->Item(2).GetListValue(),
                              aContext, aPresContext,
                              aCanStoreInRuleTree,
                              aBounds, aAppUnitsPerMatrixUnit);
   }
   double progress = aData->Item(3).GetPercentValue();
 
-  return nsStyleAnimation::InterpolateTransformMatrix(matrix1, matrix2, progress);
+  aMatrix = nsStyleAnimation::InterpolateTransformMatrix(matrix1, matrix2, progress) * aMatrix;
 }
 
 /* Helper function to process a translatex function. */
-/* static */ gfx3DMatrix
-nsStyleTransformMatrix::ProcessTranslateX(const nsCSSValue::Array* aData,
-                                          nsStyleContext* aContext,
-                                          nsPresContext* aPresContext,
-                                          PRBool& aCanStoreInRuleTree,
-                                          nsRect& aBounds, float aAppUnitsPerMatrixUnit)
+static void
+ProcessTranslateX(gfx3DMatrix& aMatrix, 
+                  const nsCSSValue::Array* aData,
+                  nsStyleContext* aContext,
+                  nsPresContext* aPresContext,
+                  PRBool& aCanStoreInRuleTree,
+                  nsRect& aBounds, float aAppUnitsPerMatrixUnit)
 {
   NS_PRECONDITION(aData->Count() == 2, "Invalid array!");
 
-  gfx3DMatrix temp;
+  gfxPoint3D temp;
 
-  /* There are two cases.  If we have a number, we want our matrix to look
-   * like this:
-   *
-   * |  1  0  0  0 |
-   * |  0  1  0  0 |
-   * |  0  0  1  0 |
-   * | dx  0  0  1 |
-   * So E = value
-   * 
-   * Otherwise, we might have a percentage, so we want to set the dX component
-   * to the percent.
-   */
-  ProcessTranslatePart(temp._41, aData->Item(1),
-                       aContext, aPresContext, aCanStoreInRuleTree,
-                       aBounds.Width(), aAppUnitsPerMatrixUnit);
-  return temp;
+  temp.x = ProcessTranslatePart(aData->Item(1),
+                                aContext, aPresContext, aCanStoreInRuleTree,
+                                aBounds.Width(), aAppUnitsPerMatrixUnit);
+  aMatrix.Translate(temp);
 }
 
 /* Helper function to process a translatey function. */
-/* static */ gfx3DMatrix
-nsStyleTransformMatrix::ProcessTranslateY(const nsCSSValue::Array* aData,
-                                          nsStyleContext* aContext,
-                                          nsPresContext* aPresContext,
-                                          PRBool& aCanStoreInRuleTree,
-                                          nsRect& aBounds, float aAppUnitsPerMatrixUnit)
+static void
+ProcessTranslateY(gfx3DMatrix& aMatrix,
+                  const nsCSSValue::Array* aData,
+                  nsStyleContext* aContext,
+                  nsPresContext* aPresContext,
+                  PRBool& aCanStoreInRuleTree,
+                  nsRect& aBounds, float aAppUnitsPerMatrixUnit)
 {
   NS_PRECONDITION(aData->Count() == 2, "Invalid array!");
 
-  gfx3DMatrix temp;
+  gfxPoint3D temp;
 
-  /* There are two cases.  If we have a number, we want our matrix to look
-   * like this:
-   *
-   * |  1  0  0  0 |
-   * |  0  1  0  0 |
-   * |  0  0  1  0 |
-   * |  0 dy  0  1 |
-   * So E = value
-   * 
-   * Otherwise, we might have a percentage, so we want to set the dY component
-   * to the percent.
-   */
-  ProcessTranslatePart(temp._42, aData->Item(1),
-                       aContext, aPresContext, aCanStoreInRuleTree,
-                       aBounds.Height(), aAppUnitsPerMatrixUnit);
-  return temp;
+  temp.y = ProcessTranslatePart(aData->Item(1),
+                                aContext, aPresContext, aCanStoreInRuleTree,
+                                aBounds.Height(), aAppUnitsPerMatrixUnit);
+  aMatrix.Translate(temp);
 }
 
-/* static */ gfx3DMatrix
-nsStyleTransformMatrix::ProcessTranslateZ(const nsCSSValue::Array* aData,
-                                          nsStyleContext* aContext,
+static void 
+ProcessTranslateZ(gfx3DMatrix& aMatrix,
+                  const nsCSSValue::Array* aData,
+                  nsStyleContext* aContext,
                                           nsPresContext* aPresContext,
                                           PRBool& aCanStoreInRuleTree,
                                           float aAppUnitsPerMatrixUnit)
 {
   NS_PRECONDITION(aData->Count() == 2, "Invalid array!");
 
-  gfx3DMatrix temp;
+  gfxPoint3D temp;
 
-  ProcessTranslatePart(temp._43, aData->Item(1),
-                       aContext, aPresContext, aCanStoreInRuleTree,
-                       0, aAppUnitsPerMatrixUnit);
-  return temp;
+  temp.z = ProcessTranslatePart(aData->Item(1),
+                                aContext, aPresContext, aCanStoreInRuleTree,
+                                0, aAppUnitsPerMatrixUnit);
+  aMatrix.Translate(temp);
 }
 
 /* Helper function to process a translate function. */
-/* static */ gfx3DMatrix
-nsStyleTransformMatrix::ProcessTranslate(const nsCSSValue::Array* aData,
-                                         nsStyleContext* aContext,
-                                         nsPresContext* aPresContext,
-                                         PRBool& aCanStoreInRuleTree,
-                                         nsRect& aBounds, float aAppUnitsPerMatrixUnit)
+static void
+ProcessTranslate(gfx3DMatrix& aMatrix,
+                 const nsCSSValue::Array* aData,
+                 nsStyleContext* aContext,
+                 nsPresContext* aPresContext,
+                 PRBool& aCanStoreInRuleTree,
+                 nsRect& aBounds, float aAppUnitsPerMatrixUnit)
 {
   NS_PRECONDITION(aData->Count() == 2 || aData->Count() == 3, "Invalid array!");
 
-  gfx3DMatrix temp;
+  gfxPoint3D temp;
 
-  ProcessTranslatePart(temp._41, aData->Item(1),
-                       aContext, aPresContext, aCanStoreInRuleTree,
-                       aBounds.Width(), aAppUnitsPerMatrixUnit);
+  temp.x = ProcessTranslatePart(aData->Item(1),
+                                aContext, aPresContext, aCanStoreInRuleTree,
+                                aBounds.Width(), aAppUnitsPerMatrixUnit);
 
   /* If we read in a Y component, set it appropriately */
   if (aData->Count() == 3) {
-    ProcessTranslatePart(temp._42, aData->Item(2),
-                         aContext, aPresContext, aCanStoreInRuleTree,
-                         aBounds.Height(), aAppUnitsPerMatrixUnit);
+    temp.y = ProcessTranslatePart(aData->Item(2),
+                                  aContext, aPresContext, aCanStoreInRuleTree,
+                                  aBounds.Height(), aAppUnitsPerMatrixUnit);
   }
-  return temp;
+  aMatrix.Translate(temp);
 }
 
-/* static */ gfx3DMatrix
-nsStyleTransformMatrix::ProcessTranslate3D(const nsCSSValue::Array* aData,
-                                           nsStyleContext* aContext,
-                                           nsPresContext* aPresContext,
-                                           PRBool& aCanStoreInRuleTree,
-                                           nsRect& aBounds, float aAppUnitsPerMatrixUnit)
+static void
+ProcessTranslate3D(gfx3DMatrix& aMatrix,
+                   const nsCSSValue::Array* aData,
+                   nsStyleContext* aContext,
+                   nsPresContext* aPresContext,
+                   PRBool& aCanStoreInRuleTree,
+                   nsRect& aBounds, float aAppUnitsPerMatrixUnit)
 {
   NS_PRECONDITION(aData->Count() == 4, "Invalid array!");
 
-  gfx3DMatrix temp;
+  gfxPoint3D temp;
 
-  ProcessTranslatePart(temp._41, aData->Item(1),
-                       aContext, aPresContext, aCanStoreInRuleTree,
-                       aBounds.Width(), aAppUnitsPerMatrixUnit);
+  temp.x = ProcessTranslatePart(aData->Item(1),
+                                aContext, aPresContext, aCanStoreInRuleTree,
+                                aBounds.Width(), aAppUnitsPerMatrixUnit);
 
-  ProcessTranslatePart(temp._42, aData->Item(2),
-                       aContext, aPresContext, aCanStoreInRuleTree,
-                       aBounds.Height(), aAppUnitsPerMatrixUnit);
+  temp.y = ProcessTranslatePart(aData->Item(2),
+                                aContext, aPresContext, aCanStoreInRuleTree,
+                                aBounds.Height(), aAppUnitsPerMatrixUnit);
 
-  ProcessTranslatePart(temp._43, aData->Item(3),
-                       aContext, aPresContext, aCanStoreInRuleTree,
-                       0, aAppUnitsPerMatrixUnit);
+  temp.z = ProcessTranslatePart(aData->Item(3),
+                                aContext, aPresContext, aCanStoreInRuleTree,
+                                0, aAppUnitsPerMatrixUnit);
 
-  return temp;
+  aMatrix.Translate(temp);
 }
 
 /* Helper function to set up a scale matrix. */
-/* static */ gfx3DMatrix
-nsStyleTransformMatrix::ProcessScaleHelper(float aXScale, float aYScale, float aZScale)
+static void
+ProcessScaleHelper(gfx3DMatrix& aMatrix,
+                   float aXScale, 
+                   float aYScale, 
+                   float aZScale)
 {
-  /* We want our matrix to look like this:
-   * | dx  0   0 0 |
-   * |  0 dy   0 0 |
-   * |  0  0  dz 0 |
-   * |  0  0   0 1 |
-   * So A = value
-   */
-  gfx3DMatrix temp;
-  temp._11 = aXScale;
-  temp._22 = aYScale;
-  temp._33 = aZScale;
-  return temp;
+  aMatrix.Scale(aXScale, aYScale, aZScale);
 }
 
 /* Process a scalex function. */
-/* static */ gfx3DMatrix
-nsStyleTransformMatrix::ProcessScaleX(const nsCSSValue::Array* aData)
+static void
+ProcessScaleX(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData)
 {
   NS_PRECONDITION(aData->Count() == 2, "Bad array!");
-  return ProcessScaleHelper(aData->Item(1).GetFloatValue(), 1.0f, 1.0f);
+  ProcessScaleHelper(aMatrix, aData->Item(1).GetFloatValue(), 1.0f, 1.0f);
 }
 
 /* Process a scaley function. */
-/* static */ gfx3DMatrix
-nsStyleTransformMatrix::ProcessScaleY(const nsCSSValue::Array* aData)
+static void
+ProcessScaleY(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData)
 {
   NS_PRECONDITION(aData->Count() == 2, "Bad array!");
-  return ProcessScaleHelper(1.0f, aData->Item(1).GetFloatValue(), 1.0f);
+  ProcessScaleHelper(aMatrix, 1.0f, aData->Item(1).GetFloatValue(), 1.0f);
 }
 
-/* static */ gfx3DMatrix
-nsStyleTransformMatrix::ProcessScaleZ(const nsCSSValue::Array* aData)
+static void
+ProcessScaleZ(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData)
 {
   NS_PRECONDITION(aData->Count() == 2, "Bad array!");
-  return ProcessScaleHelper(1.0f, 1.0f, aData->Item(1).GetFloatValue());
+  ProcessScaleHelper(aMatrix, 1.0f, 1.0f, aData->Item(1).GetFloatValue());
 }
 
-/* static */ gfx3DMatrix
-nsStyleTransformMatrix::ProcessScale3D(const nsCSSValue::Array* aData)
+static void
+ProcessScale3D(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData)
 {
   NS_PRECONDITION(aData->Count() == 4, "Bad array!");
-  return ProcessScaleHelper(aData->Item(1).GetFloatValue(),
-                            aData->Item(2).GetFloatValue(),
-                            aData->Item(3).GetFloatValue());
+  ProcessScaleHelper(aMatrix,
+                     aData->Item(1).GetFloatValue(),
+                     aData->Item(2).GetFloatValue(),
+                     aData->Item(3).GetFloatValue());
 }
 
 /* Process a scale function. */
-/* static */ gfx3DMatrix
-nsStyleTransformMatrix::ProcessScale(const nsCSSValue::Array* aData)
+static void
+ProcessScale(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData)
 {
   NS_PRECONDITION(aData->Count() == 2 || aData->Count() == 3, "Bad array!");
   /* We either have one element or two.  If we have one, it's for both X and Y.
    * Otherwise it's one for each.
    */
   const nsCSSValue& scaleX = aData->Item(1);
   const nsCSSValue& scaleY = (aData->Count() == 2 ? scaleX :
                               aData->Item(2));
 
-  return ProcessScaleHelper(scaleX.GetFloatValue(),
-                            scaleY.GetFloatValue(),
-                            1.0f);
+  ProcessScaleHelper(aMatrix, 
+                     scaleX.GetFloatValue(),
+                     scaleY.GetFloatValue(),
+                     1.0f);
 }
 
 /* Helper function that, given a set of angles, constructs the appropriate
  * skew matrix.
  */
-/* static */ gfx3DMatrix
-nsStyleTransformMatrix::ProcessSkewHelper(double aXAngle, double aYAngle)
+static void
+ProcessSkewHelper(gfx3DMatrix& aMatrix, double aXAngle, double aYAngle)
 {
-  /* We want our matrix to look like this:
-   * | 1           tan(ThetaY) 0 0 |
-   * | tan(ThetaX) 1           0 0 |
-   * | 0           0           1 0 |
-   * | 0           0           0 1 |
-   * However, to avoid infinite values, we'll use the SafeTangent function
-   * instead of the C standard tan function.
-   */
-  gfx3DMatrix temp;
-  temp._12 = SafeTangent(aYAngle);
-  temp._21 = SafeTangent(aXAngle);
-  return temp;
+  aMatrix.SkewXY(aXAngle, aYAngle);
 }
 
 /* Function that converts a skewx transform into a matrix. */
-/* static */ gfx3DMatrix
-nsStyleTransformMatrix::ProcessSkewX(const nsCSSValue::Array* aData)
+static void
+ProcessSkewX(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData)
 {
   NS_ASSERTION(aData->Count() == 2, "Bad array!");
-  return ProcessSkewHelper(aData->Item(1).GetAngleValueInRadians(), 0.0);
+  ProcessSkewHelper(aMatrix, aData->Item(1).GetAngleValueInRadians(), 0.0);
 }
 
 /* Function that converts a skewy transform into a matrix. */
-/* static */ gfx3DMatrix
-nsStyleTransformMatrix::ProcessSkewY(const nsCSSValue::Array* aData)
+static void
+ProcessSkewY(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData)
 {
   NS_ASSERTION(aData->Count() == 2, "Bad array!");
-  return ProcessSkewHelper(0.0, aData->Item(1).GetAngleValueInRadians());
+  ProcessSkewHelper(aMatrix, 0.0, aData->Item(1).GetAngleValueInRadians());
 }
 
 /* Function that converts a skew transform into a matrix. */
-/* static */ gfx3DMatrix
-nsStyleTransformMatrix::ProcessSkew(const nsCSSValue::Array* aData)
+static void
+ProcessSkew(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData)
 {
   NS_ASSERTION(aData->Count() == 2 || aData->Count() == 3, "Bad array!");
 
   double xSkew = aData->Item(1).GetAngleValueInRadians();
   double ySkew = (aData->Count() == 2
                   ? 0.0 : aData->Item(2).GetAngleValueInRadians());
 
-  return ProcessSkewHelper(xSkew, ySkew);
+  ProcessSkewHelper(aMatrix, xSkew, ySkew);
 }
 
 /* Function that converts a rotate transform into a matrix. */
-/* static */ gfx3DMatrix
-nsStyleTransformMatrix::ProcessRotateZ(const nsCSSValue::Array* aData)
+static void
+ProcessRotateZ(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData)
 {
   NS_PRECONDITION(aData->Count() == 2, "Invalid array!");
-
-  /* We want our matrix to look like this:
-   * |  cos(theta)  sin(theta)  0 0 |
-   * | -sin(theta)  cos(theta)  0 0 |
-   * |           0           0  1 0 |
-   * |           0           0  0 1 |
-   * (see http://www.w3.org/TR/SVG/coords.html#RotationDefined)
-   */
   double theta = aData->Item(1).GetAngleValueInRadians();
-  float cosTheta = FlushToZero(cos(theta));
-  float sinTheta = FlushToZero(sin(theta));
-
-  gfx3DMatrix temp;
-
-  temp._11 = cosTheta;
-  temp._12 = sinTheta;
-  temp._21 = -sinTheta;
-  temp._22 = cosTheta;
-  return temp;
+  aMatrix.RotateZ(theta);
 }
 
-/* static */ gfx3DMatrix
-nsStyleTransformMatrix::ProcessRotateX(const nsCSSValue::Array* aData)
+static void
+ProcessRotateX(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData)
 {
   NS_PRECONDITION(aData->Count() == 2, "Invalid array!");
-
-  /* We want our matrix to look like this:
-   * | 1           0           0 0 |
-   * | 0  cos(theta)  sin(theta) 0 |
-   * | 0 -sin(theta)  cos(theta) 0 |
-   * | 0           0           0 1 |
-   * (see http://www.w3.org/TR/SVG/coords.html#RotationDefined)
-   */
   double theta = aData->Item(1).GetAngleValueInRadians();
-  float cosTheta = FlushToZero(cos(theta));
-  float sinTheta = FlushToZero(sin(theta));
-
-  gfx3DMatrix temp;
-
-  temp._22 = cosTheta;
-  temp._23 = sinTheta;
-  temp._32 = -sinTheta;
-  temp._33 = cosTheta;
-  return temp;
+  aMatrix.RotateX(theta);
 }
 
-/* static */ gfx3DMatrix 
-nsStyleTransformMatrix::ProcessRotateY(const nsCSSValue::Array* aData)
+static void
+ProcessRotateY(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData)
 {
   NS_PRECONDITION(aData->Count() == 2, "Invalid array!");
-
-  /* We want our matrix to look like this:
-   * | cos(theta) 0 -sin(theta) 0 |
-   * |          0 1           0 0 |
-   * | sin(theta) 0  cos(theta) 0 |
-   * | 0          0           0 1 |
-   * (see http://www.w3.org/TR/SVG/coords.html#RotationDefined)
-   */
   double theta = aData->Item(1).GetAngleValueInRadians();
-  float cosTheta = FlushToZero(cos(theta));
-  float sinTheta = FlushToZero(sin(theta));
-
-  gfx3DMatrix temp;
-
-  temp._11 = cosTheta;
-  temp._13 = -sinTheta;
-  temp._31 = sinTheta;
-  temp._33 = cosTheta;
-  return temp;
+  aMatrix.RotateY(theta);
 }
 
-/* static */ gfx3DMatrix
-nsStyleTransformMatrix::ProcessRotate3D(const nsCSSValue::Array* aData)
+static void
+ProcessRotate3D(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData)
 {
   NS_PRECONDITION(aData->Count() == 5, "Invalid array!");
 
   /* We want our matrix to look like this:
    * |       1 + (1-cos(angle))*(x*x-1)   -z*sin(angle)+(1-cos(angle))*x*y   y*sin(angle)+(1-cos(angle))*x*z   0 |
    * |  z*sin(angle)+(1-cos(angle))*x*y         1 + (1-cos(angle))*(y*y-1)  -x*sin(angle)+(1-cos(angle))*y*z   0 |
    * | -y*sin(angle)+(1-cos(angle))*x*z    x*sin(angle)+(1-cos(angle))*y*z        1 + (1-cos(angle))*(z*z-1)   0 |
    * |                                0                                  0                                 0   1 |
@@ -579,17 +478,17 @@ nsStyleTransformMatrix::ProcessRotate3D(
 
   float x = aData->Item(1).GetFloatValue();
   float y = aData->Item(2).GetFloatValue();
   float z = aData->Item(3).GetFloatValue();
 
   /* Normalize [x,y,z] */
   float length = sqrt(x*x + y*y + z*z);
   if (length == 0.0) {
-    return gfx3DMatrix();
+    return;
   }
   x /= length;
   y /= length;
   z /= length;
 
   gfx3DMatrix temp;
 
   /* Create our matrix */
@@ -604,155 +503,167 @@ nsStyleTransformMatrix::ProcessRotate3D(
   temp._31 = -y * sinTheta + (1 - cosTheta) * x * z;
   temp._32 = x * sinTheta + (1 - cosTheta) * y * z;
   temp._33 = 1 + (1 - cosTheta) * (z * z - 1);
   temp._34 = 0.0f;
   temp._41 = 0.0f;
   temp._42 = 0.0f;
   temp._43 = 0.0f;
   temp._44 = 1.0f;
-  return temp;
+
+  aMatrix = temp * aMatrix;
 }
 
-/* static */ gfx3DMatrix
-nsStyleTransformMatrix::ProcessPerspective(const nsCSSValue::Array* aData,
-                                           nsStyleContext *aContext,
-                                           nsPresContext *aPresContext,
-                                           PRBool &aCanStoreInRuleTree,
-                                           float aAppUnitsPerMatrixUnit)
+static void 
+ProcessPerspective(gfx3DMatrix& aMatrix, 
+                   const nsCSSValue::Array* aData,
+                   nsStyleContext *aContext,
+                   nsPresContext *aPresContext,
+                   PRBool &aCanStoreInRuleTree,
+                   float aAppUnitsPerMatrixUnit)
 {
   NS_PRECONDITION(aData->Count() == 2, "Invalid array!");
 
-  /* We want our matrix to look like this:
-   * | 1 0 0        0 |
-   * | 0 1 0        0 |
-   * | 0 0 1 -1/depth |
-   * | 0 0 0        1 |
-   */
-
-  gfx3DMatrix temp;
-
-  float depth;
-  ProcessTranslatePart(depth, aData->Item(1), aContext,
-                       aPresContext, aCanStoreInRuleTree,
-                       0, aAppUnitsPerMatrixUnit);
-  NS_ASSERTION(depth > 0.0, "Perspective must be positive!");
-  temp._34 = -1.0/depth;
-
-  return temp;
+  float depth = ProcessTranslatePart(aData->Item(1), aContext,
+                                     aPresContext, aCanStoreInRuleTree,
+                                     0, aAppUnitsPerMatrixUnit);
+  aMatrix.Perspective(depth);
 }
 
-/**
- * Return the transform function, as an nsCSSKeyword, for the given
- * nsCSSValue::Array from a transform list.
- */
-/* static */ nsCSSKeyword
-nsStyleTransformMatrix::TransformFunctionOf(const nsCSSValue::Array* aData)
-{
-  nsAutoString keyword;
-  aData->Item(0).GetStringValue(keyword);
-  return nsCSSKeywords::LookupKeyword(keyword);
-}
 
 /**
  * SetToTransformFunction is essentially a giant switch statement that fans
  * out to many smaller helper functions.
  */
-gfx3DMatrix
-nsStyleTransformMatrix::MatrixForTransformFunction(const nsCSSValue::Array * aData,
-                                                   nsStyleContext* aContext,
-                                                   nsPresContext* aPresContext,
-                                                   PRBool& aCanStoreInRuleTree,
-                                                   nsRect& aBounds, 
-                                                   float aAppUnitsPerMatrixUnit)
+static void
+MatrixForTransformFunction(gfx3DMatrix& aMatrix,
+                           const nsCSSValue::Array * aData,
+                           nsStyleContext* aContext,
+                           nsPresContext* aPresContext,
+                           PRBool& aCanStoreInRuleTree,
+                           nsRect& aBounds, 
+                           float aAppUnitsPerMatrixUnit)
 {
   NS_PRECONDITION(aData, "Why did you want to get data from a null array?");
   // It's OK if aContext and aPresContext are null if the caller already
   // knows that all length units have been converted to pixels (as
   // nsStyleAnimation does).
 
 
   /* Get the keyword for the transform. */
   switch (TransformFunctionOf(aData)) {
   case eCSSKeyword_translatex:
-    return ProcessTranslateX(aData, aContext, aPresContext,
-                             aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit);
+    ProcessTranslateX(aMatrix, aData, aContext, aPresContext,
+                      aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit);
+    break;
   case eCSSKeyword_translatey:
-    return ProcessTranslateY(aData, aContext, aPresContext,
-                             aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit);
+    ProcessTranslateY(aMatrix, aData, aContext, aPresContext,
+                      aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit);
+    break;
   case eCSSKeyword_translatez:
-    return ProcessTranslateZ(aData, aContext, aPresContext,
-                             aCanStoreInRuleTree, aAppUnitsPerMatrixUnit);
+    ProcessTranslateZ(aMatrix, aData, aContext, aPresContext,
+                      aCanStoreInRuleTree, aAppUnitsPerMatrixUnit);
+    break;
   case eCSSKeyword_translate:
-    return ProcessTranslate(aData, aContext, aPresContext,
-                            aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit);
+    ProcessTranslate(aMatrix, aData, aContext, aPresContext,
+                     aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit);
+    break;
   case eCSSKeyword_translate3d:
-    return ProcessTranslate3D(aData, aContext, aPresContext,
-                              aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit);
+    ProcessTranslate3D(aMatrix, aData, aContext, aPresContext,
+                       aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit);
+    break;
   case eCSSKeyword_scalex:
-    return ProcessScaleX(aData);
+    ProcessScaleX(aMatrix, aData);
+    break;
   case eCSSKeyword_scaley:
-    return ProcessScaleY(aData);
+    ProcessScaleY(aMatrix, aData);
+    break;
   case eCSSKeyword_scalez:
-    return ProcessScaleZ(aData);
+    ProcessScaleZ(aMatrix, aData);
+    break;
   case eCSSKeyword_scale:
-      return ProcessScale(aData);
+    ProcessScale(aMatrix, aData);
+    break;
   case eCSSKeyword_scale3d:
-    return ProcessScale3D(aData);
+    ProcessScale3D(aMatrix, aData);
+    break;
   case eCSSKeyword_skewx:
-    return ProcessSkewX(aData);
+    ProcessSkewX(aMatrix, aData);
+    break;
   case eCSSKeyword_skewy:
-    return ProcessSkewY(aData);
+    ProcessSkewY(aMatrix, aData);
+    break;
   case eCSSKeyword_skew:
-    return ProcessSkew(aData);
+    ProcessSkew(aMatrix, aData);
+    break;
   case eCSSKeyword_rotatex:
-    return ProcessRotateX(aData);
+    ProcessRotateX(aMatrix, aData);
+    break;
   case eCSSKeyword_rotatey:
-    return ProcessRotateY(aData);
+    ProcessRotateY(aMatrix, aData);
+    break;
   case eCSSKeyword_rotatez:
   case eCSSKeyword_rotate:
-      return ProcessRotateZ(aData);
+    ProcessRotateZ(aMatrix, aData);
+    break;
   case eCSSKeyword_rotate3d:
-    return ProcessRotate3D(aData);
+    ProcessRotate3D(aMatrix, aData);
+    break;
   case eCSSKeyword_matrix:
-    return ProcessMatrix(aData, aContext, aPresContext,
-                         aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit);
+    ProcessMatrix(aMatrix, aData, aContext, aPresContext,
+                  aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit);
+    break;
   case eCSSKeyword_matrix3d:
-    return ProcessMatrix3D(aData, aContext, aPresContext,
-                           aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit);
+    ProcessMatrix3D(aMatrix, aData, aContext, aPresContext,
+                    aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit);
+    break;
   case eCSSKeyword_interpolatematrix:
-    return ProcessInterpolateMatrix(aData, aContext, aPresContext,
-                                    aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit);
+    ProcessInterpolateMatrix(aMatrix, aData, aContext, aPresContext,
+                             aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit);
+    break;
   case eCSSKeyword_perspective:
-    return ProcessPerspective(aData, aContext, aPresContext, 
-                              aCanStoreInRuleTree, aAppUnitsPerMatrixUnit);
+    ProcessPerspective(aMatrix, aData, aContext, aPresContext, 
+                       aCanStoreInRuleTree, aAppUnitsPerMatrixUnit);
+    break;
   default:
     NS_NOTREACHED("Unknown transform function!");
   }
-  return gfx3DMatrix();
 }
 
-/* static */ gfx3DMatrix
-nsStyleTransformMatrix::ReadTransforms(const nsCSSValueList* aList,
-                                       nsStyleContext* aContext,
-                                       nsPresContext* aPresContext,
-                                       PRBool &aCanStoreInRuleTree,
-                                       nsRect& aBounds,
-                                       float aAppUnitsPerMatrixUnit)
+/**
+ * Return the transform function, as an nsCSSKeyword, for the given
+ * nsCSSValue::Array from a transform list.
+ */
+nsCSSKeyword
+TransformFunctionOf(const nsCSSValue::Array* aData)
+{
+  nsAutoString keyword;
+  aData->Item(0).GetStringValue(keyword);
+  return nsCSSKeywords::LookupKeyword(keyword);
+}
+
+gfx3DMatrix
+ReadTransforms(const nsCSSValueList* aList,
+               nsStyleContext* aContext,
+               nsPresContext* aPresContext,
+               PRBool &aCanStoreInRuleTree,
+               nsRect& aBounds,
+               float aAppUnitsPerMatrixUnit)
 {
   gfx3DMatrix result;
 
   for (const nsCSSValueList* curr = aList; curr != nsnull; curr = curr->mNext) {
     const nsCSSValue &currElem = curr->mValue;
     NS_ASSERTION(currElem.GetUnit() == eCSSUnit_Function,
                  "Stream should consist solely of functions!");
     NS_ASSERTION(currElem.GetArrayValue()->Count() >= 1,
                  "Incoming function is too short!");
 
-    /* Read in a single transform matrix, then accumulate it with the total. */
-    result = MatrixForTransformFunction(currElem.GetArrayValue(), aContext,
-                                        aPresContext, aCanStoreInRuleTree,
-                                        aBounds, aAppUnitsPerMatrixUnit) * result;
+    /* Read in a single transform matrix. */
+    MatrixForTransformFunction(result, currElem.GetArrayValue(), aContext,
+                               aPresContext, aCanStoreInRuleTree,
+                               aBounds, aAppUnitsPerMatrixUnit);
   }
   
   return result;
 }
 
+} // namespace nsStyleTransformMatrix
--- a/layout/style/nsStyleTransformMatrix.h
+++ b/layout/style/nsStyleTransformMatrix.h
@@ -47,120 +47,44 @@
 #include "gfx3DMatrix.h"
 #include "nsRect.h"
 
 struct nsCSSValueList;
 class nsStyleContext;
 class nsPresContext;
 
 /**
- * A helper class to generate gfxMatrixes from css transform functions.
+ * A helper to generate gfxMatrixes from css transform functions.
  */
-class nsStyleTransformMatrix
-{
- public:
+namespace nsStyleTransformMatrix {
+  
   /**
    * Return the transform function, as an nsCSSKeyword, for the given
    * nsCSSValue::Array from a transform list.
    */
-  static nsCSSKeyword TransformFunctionOf(const nsCSSValue::Array* aData);
+  nsCSSKeyword TransformFunctionOf(const nsCSSValue::Array* aData);
 
   /**
-   * Given an nsCSSValue::Array* containing a -moz-transform function,
-   * returns a matrix containing the value of that function.
+   * Given an nsCSSValueList containing -moz-transform functions,
+   * returns a matrix containing the value of those functions.
    *
-   * @param aData The nsCSSValue::Array* containing the transform function.
+   * @param aData The nsCSSValueList containing the transform functions
    * @param aContext The style context, used for unit conversion.
    * @param aPresContext The presentation context, used for unit conversion.
    * @param aCanStoreInRuleTree Set to false if the result cannot be cached
    *                            in the rule tree, otherwise untouched.
    * @param aBounds The frame's bounding rectangle.
    * @param aAppUnitsPerMatrixUnit The number of app units per device pixel.
    *
    * aContext and aPresContext may be null if all of the (non-percent)
    * length values in aData are already known to have been converted to
    * eCSSUnit_Pixel (as they are in an nsStyleAnimation::Value)
    */
-  static gfx3DMatrix MatrixForTransformFunction(const nsCSSValue::Array* aData,
-                                                nsStyleContext* aContext,
-                                                nsPresContext* aPresContext,
-                                                PRBool& aCanStoreInRuleTree,
-                                                nsRect& aBounds, 
-                                                float aAppUnitsPerMatrixUnit);
-
-  /**
-   * The same as MatrixForTransformFunction, but for a list of transform
-   * functions.
-   */
-  static gfx3DMatrix ReadTransforms(const nsCSSValueList* aList,
-                                    nsStyleContext* aContext,
-                                    nsPresContext* aPresContext,
-                                    PRBool &aCanStoreInRuleTree,
-                                    nsRect& aBounds,
-                                    float aAppUnitsPerMatrixUnit);
+  gfx3DMatrix ReadTransforms(const nsCSSValueList* aList,
+                             nsStyleContext* aContext,
+                             nsPresContext* aPresContext,
+                             PRBool &aCanStoreInRuleTree,
+                             nsRect& aBounds,
+                             float aAppUnitsPerMatrixUnit);
 
- private:
-  static gfx3DMatrix ProcessMatrix(const nsCSSValue::Array *aData,
-                                   nsStyleContext *aContext,
-                                   nsPresContext *aPresContext,
-                                   PRBool &aCanStoreInRuleTree,
-                                   nsRect& aBounds, float aAppUnitsPerMatrixUnit,
-                                   PRBool *aPercentX = nsnull, 
-                                   PRBool *aPercentY = nsnull);
-  static gfx3DMatrix ProcessMatrix3D(const nsCSSValue::Array *aData,
-                                     nsStyleContext *aContext,
-                                     nsPresContext *aPresContext,
-                                     PRBool &aCanStoreInRuleTree,
-                                     nsRect& aBounds, float aAppUnitsPerMatrixUnit,
-                                     PRBool *aPercentX = nsnull, 
-                                     PRBool *aPercentY = nsnull);
-  static gfx3DMatrix ProcessInterpolateMatrix(const nsCSSValue::Array *aData,
-                                              nsStyleContext *aContext,
-                                              nsPresContext *aPresContext,
-                                              PRBool &aCanStoreInRuleTree,
-                                              nsRect& aBounds, float aAppUnitsPerMatrixUnit);
-  static gfx3DMatrix ProcessTranslateX(const nsCSSValue::Array *aData,
-                                       nsStyleContext *aContext,
-                                       nsPresContext *aPresContext,
-                                       PRBool &aCanStoreInRuleTree,
-                                       nsRect& aBounds, float aAppUnitsPerMatrixUnit);
-  static gfx3DMatrix ProcessTranslateY(const nsCSSValue::Array *aData,
-                                       nsStyleContext *aContext,
-                                       nsPresContext *aPresContext,
-                                       PRBool &aCanStoreInRuleTree,
-                                       nsRect& aBounds, float aAppUnitsPerMatrixUnit);
-  static gfx3DMatrix ProcessTranslateZ(const nsCSSValue::Array *aData,
-                                       nsStyleContext *aContext,
-                                       nsPresContext *aPresContext,
-                                       PRBool &aCanStoreInRuleTree,
-                                       float aAppUnitsPerMatrixUnit);
-  static gfx3DMatrix ProcessTranslate(const nsCSSValue::Array *aData,
-                                      nsStyleContext *aContext,
-                                      nsPresContext *aPresContext,
-                                      PRBool &aCanStoreInRuleTree,
-                                      nsRect& aBounds, float aAppUnitsPerMatrixUnit);
-  static gfx3DMatrix ProcessTranslate3D(const nsCSSValue::Array *aData,
-                                        nsStyleContext *aContext,
-                                        nsPresContext *aPresContext,
-                                        PRBool &aCanStoreInRuleTree,
-                                        nsRect& aBounds, float aAppUnitsPerMatrixUnit);
-  static gfx3DMatrix ProcessScaleHelper(float aXScale, float aYScale, float aZScale);
-  static gfx3DMatrix ProcessScaleX(const nsCSSValue::Array *aData);
-  static gfx3DMatrix ProcessScaleY(const nsCSSValue::Array *aData);
-  static gfx3DMatrix ProcessScaleZ(const nsCSSValue::Array *aData);
-  static gfx3DMatrix ProcessScale(const nsCSSValue::Array *aData);
-  static gfx3DMatrix ProcessScale3D(const nsCSSValue::Array *aData);
-  static gfx3DMatrix ProcessSkewHelper(double aXAngle, double aYAngle);
-  static gfx3DMatrix ProcessSkewX(const nsCSSValue::Array *aData);
-  static gfx3DMatrix ProcessSkewY(const nsCSSValue::Array *aData);
-  static gfx3DMatrix ProcessSkew(const nsCSSValue::Array *aData);
-  static gfx3DMatrix ProcessRotateX(const nsCSSValue::Array *aData);
-  static gfx3DMatrix ProcessRotateY(const nsCSSValue::Array *aData);
-  static gfx3DMatrix ProcessRotateZ(const nsCSSValue::Array *aData);
-  static gfx3DMatrix ProcessRotate3D(const nsCSSValue::Array *aData);
-  static gfx3DMatrix ProcessPerspective(const nsCSSValue::Array *aData,
-                                        nsStyleContext *aContext,
-                                        nsPresContext *aPresContext,
-                                        PRBool &aCanStoreInRuleTree,
-                                        float aAppUnitsPerMatrixUnit);
-};
+} // namespace nsStyleTransformMatrix
 
 #endif