Backed out 11 changesets (bug 952977) for reftest-no-accel failures
authorWes Kocher <wkocher@mozilla.com>
Tue, 29 Jul 2014 18:58:46 -0700
changeset 196744 05eb059f70bf70824fd993d237db54aae59aa1cb
parent 196743 f2a04ae4c4cf187633dd53dad36da7e8b4dbc2f9
child 196745 c2cb156aad0b6ea51dd4a34db25f866739089108
push id27223
push usercbook@mozilla.com
push dateWed, 30 Jul 2014 11:56:43 +0000
treeherderautoland@08c23f12a43e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs952977
milestone34.0a1
backs outea2367c19da34cf7312a0fed0e26beaef88e4c41
c401c8748eb34afc096868d6528d665c7d991aa0
a93e9ff1043bf8c056596d3f639998d1e72a9688
765b7f67163e84b3654f470fb0cd57330f636272
3d8cf4f5777f3efefa7e1a32d322f27cd7d650e1
8993710a3ab323c9070d27ac9a1fa9d65c158921
1298c39b745acfb2c30458ab6cc4d42bb4d89f84
be0b899fbe5eb954a99e44a2f306525dce5fa260
f69bea1f1febbd07bcce13bf40d8ff2e4e730b39
1a745777f07ef9cc4338340de0d9ea7620d80f07
5ad1d18dfe17b8b6b0ffe9d4d50a142a6bf3d3c7
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
Backed out 11 changesets (bug 952977) for reftest-no-accel failures Backed out changeset ea2367c19da3 (bug 952977) Backed out changeset c401c8748eb3 (bug 952977) Backed out changeset a93e9ff1043b (bug 952977) Backed out changeset 765b7f67163e (bug 952977) Backed out changeset 3d8cf4f5777f (bug 952977) Backed out changeset 8993710a3ab3 (bug 952977) Backed out changeset 1298c39b745a (bug 952977) Backed out changeset be0b899fbe5e (bug 952977) Backed out changeset f69bea1f1feb (bug 952977) Backed out changeset 1a745777f07e (bug 952977) Backed out changeset 5ad1d18dfe17 (bug 952977)
dom/base/nsDOMWindowUtils.cpp
gfx/2d/Matrix.h
gfx/gl/DecomposeIntoNoRepeatTriangles.h
gfx/gl/GLContext.h
gfx/ipc/GfxMessageUtils.h
gfx/layers/LayerTreeInvalidation.cpp
gfx/layers/LayersLogging.cpp
gfx/layers/ReadbackProcessor.cpp
gfx/layers/RenderTrace.cpp
gfx/layers/RenderTrace.h
gfx/layers/apz/src/APZCTreeManager.cpp
gfx/layers/apz/src/APZCTreeManager.h
gfx/layers/apz/src/AsyncPanZoomController.cpp
gfx/layers/apz/src/AsyncPanZoomController.h
gfx/layers/basic/BasicCompositor.cpp
gfx/layers/basic/BasicLayerManager.cpp
gfx/layers/client/ClientTiledThebesLayer.cpp
gfx/layers/client/TiledContentClient.cpp
gfx/layers/client/TiledContentClient.h
gfx/layers/composite/AsyncCompositionManager.cpp
gfx/layers/composite/AsyncCompositionManager.h
gfx/layers/composite/ContainerLayerComposite.cpp
gfx/layers/composite/LayerManagerComposite.cpp
gfx/layers/composite/LayerManagerComposite.h
gfx/layers/ipc/LayerTransactionParent.cpp
gfx/layers/ipc/LayerTransactionParent.h
gfx/layers/ipc/LayersMessages.ipdlh
gfx/layers/ipc/PLayerTransaction.ipdl
gfx/layers/opengl/CompositorOGL.cpp
gfx/layers/opengl/CompositorOGL.h
gfx/layers/opengl/OGLShaderProgram.h
gfx/tests/gtest/TestAsyncPanZoomController.cpp
gfx/tests/gtest/TestLayers.cpp
gfx/tests/gtest/TestLayers.h
layout/base/FrameLayerBuilder.cpp
layout/base/FrameLayerBuilder.h
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.h
layout/base/nsLayoutUtils.cpp
layout/generic/nsPageFrame.cpp
layout/generic/nsSimplePageSequenceFrame.cpp
layout/ipc/RenderFrameParent.cpp
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -3667,19 +3667,19 @@ nsDOMWindowUtils::GetOMTAStyle(nsIDOMEle
         FrameLayerBuilder::GetDedicatedLayer(frame,
                                              nsDisplayItem::TYPE_TRANSFORM);
       if (layer) {
         ShadowLayerForwarder* forwarder = layer->Manager()->AsShadowForwarder();
         if (forwarder && forwarder->HasShadowManager()) {
           MaybeTransform transform;
           forwarder->GetShadowManager()->SendGetAnimationTransform(
             layer->AsShadowableLayer()->GetShadow(), &transform);
-          if (transform.type() == MaybeTransform::TMatrix4x4) {
-            gfx3DMatrix matrix = To3DMatrix(transform.get_Matrix4x4());
-            cssValue = nsComputedDOMStyle::MatrixToCSSValue(matrix);
+          if (transform.type() == MaybeTransform::Tgfx3DMatrix) {
+            cssValue =
+              nsComputedDOMStyle::MatrixToCSSValue(transform.get_gfx3DMatrix());
           }
         }
       }
     }
   }
 
   if (cssValue) {
     nsString text;
--- a/gfx/2d/Matrix.h
+++ b/gfx/2d/Matrix.h
@@ -9,21 +9,16 @@
 #include "Types.h"
 #include "Rect.h"
 #include "Point.h"
 #include <math.h>
 
 namespace mozilla {
 namespace gfx {
 
-static bool FuzzyEqual(Float aV1, Float aV2) {
-  // XXX - Check if fabs does the smart thing and just negates the sign bit.
-  return fabs(aV2 - aV1) < 1e-6;
-}
-
 class Matrix
 {
 public:
   Matrix()
     : _11(1.0f), _12(0)
     , _21(0), _22(1.0f)
     , _31(0), _32(0)
   {}
@@ -219,26 +214,16 @@ public:
    * Returns true if the matrix has any transform other
    * than a straight translation.
    */
   bool HasNonTranslation() const {
     return !FuzzyEqual(_11, 1.0) || !FuzzyEqual(_22, 1.0) ||
            !FuzzyEqual(_12, 0.0) || !FuzzyEqual(_21, 0.0);
   }
 
-  /**
-   * Returns true if the matrix has any transform other
-   * than a translation or a -1 y scale (y axis flip)
-   */
-  bool HasNonTranslationOrFlip() const {
-      return !FuzzyEqual(_11, 1.0) ||
-             (!FuzzyEqual(_22, 1.0) && !FuzzyEqual(_22, -1.0)) ||
-             !FuzzyEqual(_21, 0.0) || !FuzzyEqual(_12, 0.0);
-  }
-
   /* Returns true if the matrix is an identity matrix.
    */
   bool IsIdentity() const
   {
     return _11 == 1.0f && _12 == 0.0f &&
            _21 == 0.0f && _22 == 1.0f &&
            _31 == 0.0f && _32 == 0.0f;
   }
@@ -289,16 +274,22 @@ public:
 
   /**
    * Returns true if the matrix has non-integer scale
    */
   bool HasNonIntegerScale() const {
       return !FuzzyEqual(_11, floor(_11 + 0.5)) ||
              !FuzzyEqual(_22, floor(_22 + 0.5));
   }
+
+private:
+  static bool FuzzyEqual(Float aV1, Float aV2) {
+    // XXX - Check if fabs does the smart thing and just negates the sign bit.
+    return fabs(aV2 - aV1) < 1e-6;
+  }
 };
 
 class Matrix4x4
 {
 public:
   Matrix4x4()
     : _11(1.0f), _12(0.0f), _13(0.0f), _14(0.0f)
     , _21(0.0f), _22(1.0f), _23(0.0f), _24(0.0f)
@@ -560,95 +551,16 @@ public:
          + _13 * _21 * _32 * _44
          - _11 * _23 * _32 * _44
          - _12 * _21 * _33 * _44
          + _11 * _22 * _33 * _44;
   }
 
   bool Invert();
 
-  void ScalePost(Float aX, Float aY, Float aZ)
-  {
-    _11 *= aX;
-    _21 *= aX;
-    _31 *= aX;
-    _41 *= aX;
-
-    _12 *= aY;
-    _22 *= aY;
-    _32 *= aY;
-    _42 *= aY;
-
-    _13 *= aZ;
-    _23 *= aZ;
-    _33 *= aZ;
-    _43 *= aZ;
-  }
-
-  void TranslatePost(Float aX, Float aY, Float aZ)
-  {
-      _11 += _14 * aX;
-      _21 += _24 * aX;
-      _31 += _34 * aX;
-      _41 += _44 * aX;
-
-      _12 += _14 * aY;
-      _22 += _24 * aY;
-      _32 += _34 * aY;
-      _42 += _44 * aY;
-
-      _13 += _14 * aZ;
-      _23 += _24 * aZ;
-      _33 += _34 * aZ;
-      _43 += _44 * aZ;
-  }
-
-  bool FuzzyEqual(const Matrix4x4& o) const
-  {
-    return gfx::FuzzyEqual(_11, o._11) && gfx::FuzzyEqual(_12, o._12) &&
-           gfx::FuzzyEqual(_13, o._13) && gfx::FuzzyEqual(_14, o._14) &&
-           gfx::FuzzyEqual(_21, o._21) && gfx::FuzzyEqual(_22, o._22) &&
-           gfx::FuzzyEqual(_23, o._23) && gfx::FuzzyEqual(_24, o._24) &&
-           gfx::FuzzyEqual(_31, o._31) && gfx::FuzzyEqual(_32, o._32) &&
-           gfx::FuzzyEqual(_33, o._33) && gfx::FuzzyEqual(_34, o._34) &&
-           gfx::FuzzyEqual(_41, o._41) && gfx::FuzzyEqual(_42, o._42) &&
-           gfx::FuzzyEqual(_43, o._43) && gfx::FuzzyEqual(_44, o._44);
-  }
-
-  bool IsBackfaceVisible() const
-  {
-    // Inverse()._33 < 0;
-    Float det = Determinant();
-    Float __33 = _12*_24*_41 - _14*_22*_41 +
-                _14*_21*_42 - _11*_24*_42 -
-                _12*_21*_44 + _11*_22*_44;
-    return (__33 * det) < 0;
-  }
-
-  void NudgeToIntegersFixedEpsilon()
-  {
-    static const float error = 1e-5f;
-    NudgeToInteger(&_11, error);
-    NudgeToInteger(&_12, error);
-    NudgeToInteger(&_13, error);
-    NudgeToInteger(&_14, error);
-    NudgeToInteger(&_21, error);
-    NudgeToInteger(&_22, error);
-    NudgeToInteger(&_23, error);
-    NudgeToInteger(&_24, error);
-    NudgeToInteger(&_31, error);
-    NudgeToInteger(&_32, error);
-    NudgeToInteger(&_33, error);
-    NudgeToInteger(&_34, error);
-    NudgeToInteger(&_41, error);
-    NudgeToInteger(&_42, error);
-    NudgeToInteger(&_43, error);
-    NudgeToInteger(&_44, error);
-  }
-
   // Set all the members of the matrix to NaN
   void SetNAN();
 };
 
 class Matrix5x4
 {
 public:
   Matrix5x4()
--- a/gfx/gl/DecomposeIntoNoRepeatTriangles.h
+++ b/gfx/gl/DecomposeIntoNoRepeatTriangles.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef DecomposeIntoNoRepeatTriangles_h_
 #define DecomposeIntoNoRepeatTriangles_h_
 
 #include "GLTypes.h"
 #include "nsRect.h"
 #include "nsTArray.h"
+#include "gfx3DMatrix.h"
 
 namespace mozilla {
 namespace gl {
 
 /** Helper for DecomposeIntoNoRepeatTriangles
   */
 class RectTriangles {
 public:
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -24,16 +24,17 @@
 #ifdef GetClassName
 #undef GetClassName
 #endif
 
 #include "mozilla/UniquePtr.h"
 
 #include "GLDefs.h"
 #include "GLLibraryLoader.h"
+#include "gfx3DMatrix.h"
 #include "nsISupportsImpl.h"
 #include "plstr.h"
 #include "nsDataHashtable.h"
 #include "nsHashKeys.h"
 #include "nsAutoPtr.h"
 #include "GLContextTypes.h"
 #include "GLTextureImage.h"
 #include "SurfaceTypes.h"
--- a/gfx/ipc/GfxMessageUtils.h
+++ b/gfx/ipc/GfxMessageUtils.h
@@ -8,21 +8,21 @@
 #define __GFXMESSAGEUTILS_H__
 
 #include "base/process_util.h"
 #include "chrome/common/ipc_message_utils.h"
 #include "ipc/IPCMessageUtils.h"
 
 #include <stdint.h>
 
+#include "gfx3DMatrix.h"
 #include "gfxColor.h"
 #include "mozilla/gfx/Matrix.h"
 #include "GraphicsFilter.h"
 #include "gfxPoint.h"
-#include "gfxPoint3D.h"
 #include "gfxRect.h"
 #include "nsRect.h"
 #include "nsRegion.h"
 #include "gfxTypes.h"
 #include "mozilla/layers/LayersTypes.h"
 #include "mozilla/layers/CompositorTypes.h"
 #include "FrameMetrics.h"
 #include "FilterSupport.h"
@@ -212,16 +212,42 @@ struct ParamTraits<gfxRect>
   {
     return ReadParam(aMsg, aIter, &aResult->x) &&
            ReadParam(aMsg, aIter, &aResult->y) &&
            ReadParam(aMsg, aIter, &aResult->width) &&
            ReadParam(aMsg, aIter, &aResult->height);
   }
 };
 
+template<>
+struct ParamTraits<gfx3DMatrix>
+{
+  typedef gfx3DMatrix paramType;
+
+  static void Write(Message* msg, const paramType& param)
+  {
+#define Wr(_f)  WriteParam(msg, param. _f)
+    Wr(_11); Wr(_12); Wr(_13); Wr(_14);
+    Wr(_21); Wr(_22); Wr(_23); Wr(_24);
+    Wr(_31); Wr(_32); Wr(_33); Wr(_34);
+    Wr(_41); Wr(_42); Wr(_43); Wr(_44);
+#undef Wr
+  }
+
+  static bool Read(const Message* msg, void** iter, paramType* result)
+  {
+#define Rd(_f)  ReadParam(msg, iter, &result-> _f)
+    return (Rd(_11) && Rd(_12) && Rd(_13) && Rd(_14) &&
+            Rd(_21) && Rd(_22) && Rd(_23) && Rd(_24) &&
+            Rd(_31) && Rd(_32) && Rd(_33) && Rd(_34) &&
+            Rd(_41) && Rd(_42) && Rd(_43) && Rd(_44));
+#undef Rd
+  }
+};
+
 template <>
 struct ParamTraits<gfxContentType>
   : public ContiguousTypedEnumSerializer<
              gfxContentType,
              gfxContentType::COLOR,
              gfxContentType::SENTINEL>
 {};
 
--- a/gfx/layers/LayerTreeInvalidation.cpp
+++ b/gfx/layers/LayerTreeInvalidation.cpp
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "LayerTreeInvalidation.h"
 #include <stdint.h>                     // for uint32_t
 #include "ImageContainer.h"             // for ImageContainer
 #include "ImageLayers.h"                // for ImageLayer, etc
 #include "Layers.h"                     // for Layer, ContainerLayer, etc
+#include "gfx3DMatrix.h"                // for gfx3DMatrix
 #include "gfxColor.h"                   // for gfxRGBA
 #include "GraphicsFilter.h"             // for GraphicsFilter
 #include "gfxPoint3D.h"                 // for gfxPoint3D
 #include "gfxRect.h"                    // for gfxRect
 #include "gfxUtils.h"                   // for gfxUtils
 #include "mozilla/gfx/BaseSize.h"       // for BaseSize
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/mozalloc.h"           // for operator new, etc
@@ -20,45 +21,43 @@
 #include "nsDataHashtable.h"            // for nsDataHashtable
 #include "nsDebug.h"                    // for NS_ASSERTION
 #include "nsHashKeys.h"                 // for nsPtrHashKey
 #include "nsISupportsImpl.h"            // for Layer::AddRef, etc
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsRect.h"                     // for nsIntRect
 #include "nsTArray.h"                   // for nsAutoTArray, nsTArray_Impl
 
-using namespace mozilla::gfx;
-
 namespace mozilla {
 namespace layers {
 
 struct LayerPropertiesBase;
 LayerPropertiesBase* CloneLayerTreePropertiesInternal(Layer* aRoot);
 
 static nsIntRect
-TransformRect(const nsIntRect& aRect, const Matrix4x4& aTransform)
+TransformRect(const nsIntRect& aRect, const gfx3DMatrix& aTransform)
 {
   if (aRect.IsEmpty()) {
     return nsIntRect();
   }
 
-  Rect rect(aRect.x, aRect.y, aRect.width, aRect.height);
+  gfxRect rect(aRect.x, aRect.y, aRect.width, aRect.height);
   rect = aTransform.TransformBounds(rect);
   rect.RoundOut();
 
   nsIntRect intRect;
-  if (!gfxUtils::GfxRectToIntRect(ThebesRect(rect), &intRect)) {
+  if (!gfxUtils::GfxRectToIntRect(rect, &intRect)) {
     return nsIntRect();
   }
 
   return intRect;
 }
 
 static void
-AddTransformedRegion(nsIntRegion& aDest, const nsIntRegion& aSource, const Matrix4x4& aTransform)
+AddTransformedRegion(nsIntRegion& aDest, const nsIntRegion& aSource, const gfx3DMatrix& aTransform)
 {
   nsIntRegionRectIterator iter(aSource);
   const nsIntRect *r;
   while ((r = iter.Next())) {
     aDest.Or(aDest, TransformRect(*r, aTransform));
   }
   aDest.SimplifyOutward(20);
 }
@@ -110,17 +109,17 @@ struct LayerPropertiesBase : public Laye
   {
     MOZ_COUNT_CTOR(LayerPropertiesBase);
     if (aLayer->GetMaskLayer()) {
       mMaskLayer = CloneLayerTreePropertiesInternal(aLayer->GetMaskLayer());
     }
     if (mUseClipRect) {
       mClipRect = *aLayer->GetClipRect();
     }
-    mTransform = aLayer->GetTransform();
+    mTransform = gfx::To3DMatrix(aLayer->GetTransform());
   }
   LayerPropertiesBase()
     : mLayer(nullptr)
     , mMaskLayer(nullptr)
   {
     MOZ_COUNT_CTOR(LayerPropertiesBase);
   }
   ~LayerPropertiesBase()
@@ -132,17 +131,18 @@ struct LayerPropertiesBase : public Laye
                                          NotifySubDocInvalidationFunc aCallback,
                                          bool* aGeometryChanged);
 
   virtual void MoveBy(const nsIntPoint& aOffset);
 
   nsIntRegion ComputeChange(NotifySubDocInvalidationFunc aCallback,
                             bool& aGeometryChanged)
   {
-    bool transformChanged = !mTransform.FuzzyEqual(mLayer->GetTransform()) ||
+    gfx3DMatrix transform = gfx::To3DMatrix(mLayer->GetTransform());
+    bool transformChanged = !mTransform.FuzzyEqual(transform) ||
                             mLayer->GetPostXScale() != mPostXScale ||
                             mLayer->GetPostYScale() != mPostYScale;
     Layer* otherMask = mLayer->GetMaskLayer();
     const nsIntRect* otherClip = mLayer->GetClipRect();
     nsIntRegion result;
     if ((mMaskLayer ? mMaskLayer->mLayer : nullptr) != otherMask ||
         (mUseClipRect != !!otherClip) ||
         mLayer->GetLocalOpacity() != mOpacity ||
@@ -179,17 +179,18 @@ struct LayerPropertiesBase : public Laye
     }
 
     mLayer->ClearInvalidRect();
     return result;
   }
 
   nsIntRect NewTransformedBounds()
   {
-    return TransformRect(mLayer->GetVisibleRegion().GetBounds(), mLayer->GetTransform());
+    return TransformRect(mLayer->GetVisibleRegion().GetBounds(),
+                         gfx::To3DMatrix(mLayer->GetTransform()));
   }
 
   nsIntRect OldTransformedBounds()
   {
     return TransformRect(mVisibleRegion.GetBounds(), mTransform);
   }
 
   virtual nsIntRegion ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback,
@@ -197,17 +198,17 @@ struct LayerPropertiesBase : public Laye
   {
     return nsIntRect();
   }
 
   nsRefPtr<Layer> mLayer;
   nsAutoPtr<LayerPropertiesBase> mMaskLayer;
   nsIntRegion mVisibleRegion;
   nsIntRegion mInvalidRegion;
-  Matrix4x4 mTransform;
+  gfx3DMatrix mTransform;
   float mPostXScale;
   float mPostYScale;
   float mOpacity;
   nsIntRect mClipRect;
   bool mUseClipRect;
 };
 
 struct ContainerLayerProperties : public LayerPropertiesBase
@@ -286,17 +287,18 @@ struct ContainerLayerProperties : public
           invalidateChildsCurrentArea = true;
         }
       } else {
         // |child| is new, or was reordered to a higher index
         invalidateChildsCurrentArea = true;
       }
       if (invalidateChildsCurrentArea) {
         aGeometryChanged = true;
-        AddTransformedRegion(result, child->GetVisibleRegion(), child->GetTransform());
+        AddTransformedRegion(result, child->GetVisibleRegion(),
+                             gfx::To3DMatrix(child->GetTransform()));
         if (aCallback) {
           NotifySubdocumentInvalidationRecursive(child, aCallback);
         } else {
           ClearInvalidations(child);
         }
       }
     }
 
@@ -435,33 +437,33 @@ LayerPropertiesBase::ComputeDifferences(
 {
   NS_ASSERTION(aRoot, "Must have a layer tree to compare against!");
   if (mLayer != aRoot) {
     if (aCallback) {
       NotifySubdocumentInvalidationRecursive(aRoot, aCallback);
     } else {
       ClearInvalidations(aRoot);
     }
-    nsIntRect result = TransformRect(aRoot->GetVisibleRegion().GetBounds(),
-                                     aRoot->GetTransform());
+    gfx3DMatrix transform = gfx::To3DMatrix(aRoot->GetTransform());
+    nsIntRect result = TransformRect(aRoot->GetVisibleRegion().GetBounds(), transform);
     result = result.Union(OldTransformedBounds());
     if (aGeometryChanged != nullptr) {
       *aGeometryChanged = true;
     }
     return result;
   } else {
     bool geometryChanged = (aGeometryChanged != nullptr) ? *aGeometryChanged : false;
     nsIntRegion invalid = ComputeChange(aCallback, geometryChanged);
     if (aGeometryChanged != nullptr) {
       *aGeometryChanged = geometryChanged;
     }
     return invalid;
   }
 }
-
-void
+  
+void 
 LayerPropertiesBase::MoveBy(const nsIntPoint& aOffset)
 {
-  mTransform.TranslatePost(aOffset.x, aOffset.y, 0);
+  mTransform.TranslatePost(gfxPoint3D(aOffset.x, aOffset.y, 0)); 
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/LayersLogging.cpp
+++ b/gfx/layers/LayersLogging.cpp
@@ -2,16 +2,17 @@
  * vim: sw=2 ts=8 et :
  */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "LayersLogging.h"
 #include <stdint.h>                     // for uint8_t
+#include "gfx3DMatrix.h"                // for gfx3DMatrix
 #include "gfxColor.h"                   // for gfxRGBA
 #include "mozilla/gfx/Matrix.h"         // for Matrix4x4, Matrix
 #include "nsDebug.h"                    // for NS_ERROR
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsRect.h"                     // for nsIntRect
 #include "nsSize.h"                     // for nsIntSize
 
 using namespace mozilla::gfx;
--- a/gfx/layers/ReadbackProcessor.cpp
+++ b/gfx/layers/ReadbackProcessor.cpp
@@ -2,16 +2,17 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ReadbackProcessor.h"
 #include <sys/types.h>                  // for int32_t
 #include "Layers.h"                     // for Layer, ThebesLayer, etc
 #include "ReadbackLayer.h"              // for ReadbackLayer, ReadbackSink
+#include "gfx3DMatrix.h"                // for gfx3DMatrix
 #include "gfxColor.h"                   // for gfxRGBA
 #include "gfxContext.h"                 // for gfxContext
 #include "gfxRect.h"                    // for gfxRect
 #include "mozilla/gfx/BasePoint.h"      // for BasePoint
 #include "mozilla/gfx/BaseRect.h"       // for BaseRect
 #include "nsAutoPtr.h"                  // for nsRefPtr, nsAutoPtr
 #include "nsDebug.h"                    // for NS_ASSERTION
 #include "nsISupportsImpl.h"            // for gfxContext::Release, etc
--- a/gfx/layers/RenderTrace.cpp
+++ b/gfx/layers/RenderTrace.cpp
@@ -19,24 +19,24 @@ static gfx::Matrix4x4 GetRootTransform(L
   gfx::Matrix4x4 layerTrans = aLayer->GetTransform();
   layerTrans.ProjectTo2D();
   if (aLayer->GetParent() != nullptr) {
     return GetRootTransform(aLayer->GetParent()) * layerTrans;
   }
   return layerTrans;
 }
 
-void RenderTraceLayers(Layer *aLayer, const char *aColor, const gfx::Matrix4x4 aRootTransform, bool aReset) {
+void RenderTraceLayers(Layer *aLayer, const char *aColor, const gfx3DMatrix aRootTransform, bool aReset) {
   if (!aLayer)
     return;
 
-  gfx::Matrix4x4 trans = aRootTransform * aLayer->GetTransform();
+  gfx3DMatrix trans = aRootTransform * aLayer->GetTransform();
   trans.ProjectTo2D();
   nsIntRect clipRect = aLayer->GetEffectiveVisibleRegion().GetBounds();
-  Rect rect(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
+  gfxRect rect(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
   trans.TransformBounds(rect);
 
   if (strcmp(aLayer->Name(), "ContainerLayer") != 0 &&
       strcmp(aLayer->Name(), "ContainerLayerComposite") != 0) {
     printf_stderr("%s RENDERTRACE %u rect #%02X%s %i %i %i %i\n",
       aLayer->Name(), (int)PR_IntervalNow(),
       colorId, aColor,
       (int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height);
--- a/gfx/layers/RenderTrace.h
+++ b/gfx/layers/RenderTrace.h
@@ -10,25 +10,25 @@
 // For the front end see: https://github.com/staktrace/rendertrace
 
 // Uncomment this line to enable RENDERTRACE
 //#define MOZ_RENDERTRACE
 
 #ifndef GFX_RENDERTRACE_H
 #define GFX_RENDERTRACE_H
 
+#include "gfx3DMatrix.h"
 #include "nsRect.h"
-#include "mozilla/gfx/Matrix.h"
 
 namespace mozilla {
 namespace layers {
 
 class Layer;
 
-void RenderTraceLayers(Layer *aLayer, const char *aColor, const gfx::Matrix4x4 aRootTransform = gfx::Matrix4x4(), bool aReset = true);
+void RenderTraceLayers(Layer *aLayer, const char *aColor, const gfx3DMatrix aRootTransform = gfx3DMatrix(), bool aReset = true);
 
 void RenderTraceInvalidateStart(Layer *aLayer, const char *aColor, const nsIntRect aRect);
 void RenderTraceInvalidateEnd(Layer *aLayer, const char *aColor);
 
 void renderTraceEventStart(const char *aComment, const char *aColor);
 void renderTraceEventEnd(const char *aComment, const char *aColor);
 void renderTraceEventEnd(const char *aColor);
 
@@ -44,17 +44,17 @@ public:
     renderTraceEventEnd(mComment, mColor);
   }
 private:
   const char *mComment;
   const char *mColor;
 };
 
 #ifndef MOZ_RENDERTRACE
-inline void RenderTraceLayers(Layer *aLayer, const char *aColor, const gfx::Matrix4x4 aRootTransform, bool aReset)
+inline void RenderTraceLayers(Layer *aLayer, const char *aColor, const gfx3DMatrix aRootTransform, bool aReset)
 {}
 
 inline void RenderTraceInvalidateStart(Layer *aLayer, const char *aColor, const nsIntRect aRect)
 {}
 
 inline void RenderTraceInvalidateEnd(Layer *aLayer, const char *aColor)
 {}
 
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "APZCTreeManager.h"
 #include "Compositor.h"                 // for Compositor
 #include "CompositorParent.h"           // for CompositorParent, etc
 #include "InputData.h"                  // for InputData, etc
 #include "Layers.h"                     // for ContainerLayer, Layer, etc
+#include "gfx3DMatrix.h"                // for gfx3DMatrix
 #include "mozilla/dom/Touch.h"          // for Touch
 #include "mozilla/gfx/Point.h"          // for Point
 #include "mozilla/layers/AsyncCompositionManager.h" // for ViewTransform
 #include "mozilla/layers/AsyncPanZoomController.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/mozalloc.h"           // for operator new
 #include "mozilla/TouchEvents.h"
 #include "mozilla/Preferences.h"        // for Preferences
@@ -26,19 +27,16 @@
 #include <algorithm>                    // for std::stable_sort
 
 #define APZCTM_LOG(...)
 // #define APZCTM_LOG(...) printf_stderr("APZCTM: " __VA_ARGS__)
 
 namespace mozilla {
 namespace layers {
 
-typedef mozilla::gfx::Point Point;
-typedef mozilla::gfx::Matrix4x4 Matrix4x4;
-
 float APZCTreeManager::sDPI = 160.0;
 
 APZCTreeManager::APZCTreeManager()
     : mTreeLock("APZCTreeLock"),
       mInOverscrolledApzc(false),
       mRetainedTouchIdentifier(-1),
       mTouchCount(0),
       mApzcTreeLog("apzctree")
@@ -136,43 +134,43 @@ APZCTreeManager::UpdatePanZoomController
   APZPaintLogHelper paintLogger(testData, aPaintSequenceNumber);
 
   if (aRoot) {
     mApzcTreeLog << "[start]\n";
     UpdatePanZoomControllerTree(aCompositor,
                                 aRoot,
                                 // aCompositor is null in gtest scenarios
                                 aCompositor ? aCompositor->RootLayerTreeId() : 0,
-                                Matrix4x4(), nullptr, nullptr,
+                                gfx3DMatrix(), nullptr, nullptr,
                                 aIsFirstPaint, aOriginatingLayersId,
                                 paintLogger, &apzcsToDestroy, nsIntRegion());
     mApzcTreeLog << "[end]\n";
   }
 
   for (size_t i = 0; i < apzcsToDestroy.Length(); i++) {
     APZCTM_LOG("Destroying APZC at %p\n", apzcsToDestroy[i].get());
     apzcsToDestroy[i]->Destroy();
   }
 }
 
 AsyncPanZoomController*
 APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor,
                                              Layer* aLayer, uint64_t aLayersId,
-                                             Matrix4x4 aTransform,
+                                             gfx3DMatrix aTransform,
                                              AsyncPanZoomController* aParent,
                                              AsyncPanZoomController* aNextSibling,
                                              bool aIsFirstPaint,
                                              uint64_t aOriginatingLayersId,
                                              const APZPaintLogHelper& aPaintLogger,
                                              nsTArray< nsRefPtr<AsyncPanZoomController> >* aApzcsToDestroy,
                                              const nsIntRegion& aObscured)
 {
   mTreeLock.AssertCurrentThreadOwns();
 
-  Matrix4x4 transform = aLayer->GetTransform();
+  gfx3DMatrix transform = gfx::To3DMatrix(aLayer->GetTransform());
 
   ContainerLayer* container = aLayer->AsContainerLayer();
   AsyncPanZoomController* apzc = nullptr;
   mApzcTreeLog << aLayer->Name() << '\t';
   if (container) {
     const FrameMetrics& metrics = container->GetFrameMetrics();
     if (metrics.IsScrollable()) {
       const CompositorParent::LayerTreeState* state = CompositorParent::GetIndirectShadowTree(aLayersId);
@@ -316,17 +314,17 @@ APZCTreeManager::UpdatePanZoomController
 
     container->SetAsyncPanZoomController(apzc);
   }
   mApzcTreeLog << '\n';
 
   // Accumulate the CSS transform between layers that have an APZC, but exclude any
   // any layers that do have an APZC, and reset the accumulation at those layers.
   if (apzc) {
-    aTransform = Matrix4x4();
+    aTransform = gfx3DMatrix();
   } else {
     // Multiply child layer transforms on the left so they get applied first
     aTransform = transform * aTransform;
   }
 
   uint64_t childLayersId = (aLayer->AsRefLayer() ? aLayer->AsRefLayer()->GetReferentId() : aLayersId);
 
   nsIntRegion obscured;
@@ -338,17 +336,17 @@ APZCTreeManager::UpdatePanZoomController
     // an empty obscured region because nothing in the parent process will
     // obscure the child process. This may be false. However, not doing this
     // definitely runs into a problematic case where the B2G notification
     // bar and the keyboard get merged into a single layer that obscures
     // all child processes, even though visually they do not. We'd probably
     // have to check for mask layers and so on in order to properly handle
     // that case.
     obscured = aObscured;
-    obscured.Transform(To3DMatrix(transform).Inverse());
+    obscured.Transform(transform.Inverse());
   }
 
   // If there's no APZC at this level, any APZCs for our child layers will
   // have our siblings as siblings.
   AsyncPanZoomController* next = apzc ? nullptr : aNextSibling;
   for (Layer* child = aLayer->GetLastChild(); child; child = child->GetPrevSibling()) {
     gfx::TreeAutoIndent indent(mApzcTreeLog);
     next = UpdatePanZoomControllerTree(aCompositor, child, childLayersId, aTransform, aParent, next,
@@ -375,54 +373,54 @@ APZCTreeManager::UpdatePanZoomController
   }
   if (next) {
     return next;
   }
   return aNextSibling;
 }
 
 /*static*/ template<class T> void
-ApplyTransform(gfx::PointTyped<T>* aPoint, const Matrix4x4& aMatrix)
+ApplyTransform(gfx::PointTyped<T>* aPoint, const gfx3DMatrix& aMatrix)
 {
-  Point result = aMatrix * aPoint->ToUnknownPoint();
+  gfxPoint result = aMatrix.Transform(gfxPoint(aPoint->x, aPoint->y));
   aPoint->x = result.x;
   aPoint->y = result.y;
 }
 
 /*static*/ template<class T> void
-ApplyTransform(gfx::IntPointTyped<T>* aPoint, const Matrix4x4& aMatrix)
+ApplyTransform(gfx::IntPointTyped<T>* aPoint, const gfx3DMatrix& aMatrix)
 {
-  Point result = aMatrix * aPoint->ToUnknownPoint();
-  aPoint->x = result.x;
-  aPoint->y = result.y;
+  gfxPoint result = aMatrix.Transform(gfxPoint(aPoint->x, aPoint->y));
+  aPoint->x = NS_lround(result.x);
+  aPoint->y = NS_lround(result.y);
 }
 
 /*static*/ void
-ApplyTransform(nsIntPoint* aPoint, const Matrix4x4& aMatrix)
+ApplyTransform(nsIntPoint* aPoint, const gfx3DMatrix& aMatrix)
 {
-  Point result = aMatrix * Point(aPoint->x, aPoint->y);
+  gfxPoint result = aMatrix.Transform(gfxPoint(aPoint->x, aPoint->y));
   aPoint->x = NS_lround(result.x);
   aPoint->y = NS_lround(result.y);
 }
 
 /*static*/ template<class T> void
 TransformScreenToGecko(T* aPoint, AsyncPanZoomController* aApzc, APZCTreeManager* aApzcTm)
 {
-  Matrix4x4 transformToApzc, transformToGecko;
+  gfx3DMatrix transformToApzc, transformToGecko;
   aApzcTm->GetInputTransforms(aApzc, transformToApzc, transformToGecko);
   ApplyTransform(aPoint, transformToApzc * transformToGecko);
 }
 
 nsEventStatus
 APZCTreeManager::ReceiveInputEvent(InputData& aEvent,
                                    ScrollableLayerGuid* aOutTargetGuid)
 {
   nsEventStatus result = nsEventStatus_eIgnore;
-  Matrix4x4 transformToApzc;
-  Matrix4x4 transformToGecko;
+  gfx3DMatrix transformToApzc;
+  gfx3DMatrix transformToGecko;
   switch (aEvent.mInputType) {
     case MULTITOUCH_INPUT: {
       MultiTouchInput& touchInput = aEvent.AsMultiTouchInput();
       result = ProcessTouchInput(touchInput, aOutTargetGuid);
       break;
     } case PANGESTURE_INPUT: {
       PanGestureInput& panInput = aEvent.AsPanGestureInput();
       bool inOverscrolledApzc = false;
@@ -556,21 +554,21 @@ APZCTreeManager::ProcessTouchInput(Multi
         MultiTouchInput cancel(MultiTouchInput::MULTITOUCH_CANCEL, 0, TimeStamp::Now(), 0);
         mApzcForInputBlock->ReceiveInputEvent(cancel);
       }
       mApzcForInputBlock = apzc;
     }
 
     if (mApzcForInputBlock) {
       // Cache apz transform so it can be used for future events in this block.
-      Matrix4x4 transformToGecko;
+      gfx3DMatrix transformToGecko;
       GetInputTransforms(mApzcForInputBlock, mCachedTransformToApzcForInputBlock, transformToGecko);
     } else {
       // Reset the cached apz transform
-      mCachedTransformToApzcForInputBlock = Matrix4x4();
+      mCachedTransformToApzcForInputBlock = gfx3DMatrix();
     }
   } else if (mApzcForInputBlock) {
     APZCTM_LOG("Re-using APZC %p as continuation of event block\n", mApzcForInputBlock.get());
   }
 
   // If we receive a touch-cancel, it means all touches are finished, so we
   // can stop ignoring any that we were ignoring.
   if (aInput.mType == MultiTouchInput::MULTITOUCH_CANCEL) {
@@ -593,29 +591,29 @@ APZCTreeManager::ProcessTouchInput(Multi
     }
   }
 
   if (mApzcForInputBlock) {
     mApzcForInputBlock->GetGuid(aOutTargetGuid);
     // For computing the input for the APZC, used the cached transform.
     // This ensures that the sequence of touch points an APZC sees in an
     // input block are all in the same coordinate space.
-    Matrix4x4 transformToApzc = mCachedTransformToApzcForInputBlock;
+    gfx3DMatrix transformToApzc = mCachedTransformToApzcForInputBlock;
     MultiTouchInput inputForApzc(aInput);
     for (size_t i = 0; i < inputForApzc.mTouches.Length(); i++) {
       ApplyTransform(&(inputForApzc.mTouches[i].mScreenPoint), transformToApzc);
     }
     mApzcForInputBlock->ReceiveInputEvent(inputForApzc);
 
     // For computing the event to pass back to Gecko, use the up-to-date transforms.
     // This ensures that transformToApzc and transformToGecko are in sync
     // (note that transformToGecko isn't cached).
-    Matrix4x4 transformToGecko;
+    gfx3DMatrix transformToGecko;
     GetInputTransforms(mApzcForInputBlock, transformToApzc, transformToGecko);
-    Matrix4x4 outTransform = transformToApzc * transformToGecko;
+    gfx3DMatrix outTransform = transformToApzc * transformToGecko;
     for (size_t i = 0; i < aInput.mTouches.Length(); i++) {
       ApplyTransform(&(aInput.mTouches[i].mScreenPoint), outTransform);
     }
   }
 
   nsEventStatus result = mInOverscrolledApzc ? nsEventStatus_eConsumeNoDefault
                        : mApzcForInputBlock ? nsEventStatus_eConsumeDoDefault
                        : nsEventStatus_eIgnore;
@@ -646,20 +644,20 @@ APZCTreeManager::ProcessTouchInput(Multi
 
 void
 APZCTreeManager::TransformCoordinateToGecko(const ScreenIntPoint& aPoint,
                                             LayoutDeviceIntPoint* aOutTransformedPoint)
 {
   MOZ_ASSERT(aOutTransformedPoint);
   nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aPoint, nullptr);
   if (apzc && aOutTransformedPoint) {
-    Matrix4x4 transformToApzc;
-    Matrix4x4 transformToGecko;
+    gfx3DMatrix transformToApzc;
+    gfx3DMatrix transformToGecko;
     GetInputTransforms(apzc, transformToApzc, transformToGecko);
-    Matrix4x4 outTransform = transformToApzc * transformToGecko;
+    gfx3DMatrix outTransform = transformToApzc * transformToGecko;
     aOutTransformedPoint->x = aPoint.x;
     aOutTransformedPoint->y = aPoint.y;
     ApplyTransform(aOutTransformedPoint, outTransform);
   }
 }
 
 nsEventStatus
 APZCTreeManager::ProcessEvent(WidgetInputEvent& aEvent,
@@ -669,20 +667,20 @@ APZCTreeManager::ProcessEvent(WidgetInpu
 
   // Transform the refPoint.
   // If the event hits an overscrolled APZC, instruct the caller to ignore it.
   bool inOverscrolledApzc = false;
   nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(ScreenPoint(aEvent.refPoint.x, aEvent.refPoint.y),
                                                         &inOverscrolledApzc);
   if (apzc) {
     apzc->GetGuid(aOutTargetGuid);
-    Matrix4x4 transformToApzc;
-    Matrix4x4 transformToGecko;
+    gfx3DMatrix transformToApzc;
+    gfx3DMatrix transformToGecko;
     GetInputTransforms(apzc, transformToApzc, transformToGecko);
-    Matrix4x4 outTransform = transformToApzc * transformToGecko;
+    gfx3DMatrix outTransform = transformToApzc * transformToGecko;
     ApplyTransform(&(aEvent.refPoint), outTransform);
   }
   return inOverscrolledApzc ? nsEventStatus_eConsumeNoDefault
        : apzc ? nsEventStatus_eConsumeDoDefault
        : nsEventStatus_eIgnore;
 }
 
 nsEventStatus
@@ -801,25 +799,23 @@ APZCTreeManager::ClearTree()
  * @param aEndPoint the end point of the displacement
  */
 static void
 TransformDisplacement(APZCTreeManager* aTreeManager,
                       AsyncPanZoomController* aSource,
                       AsyncPanZoomController* aTarget,
                       ScreenPoint& aStartPoint,
                       ScreenPoint& aEndPoint) {
-  Matrix4x4 transformToApzc;
-  Matrix4x4 transformToGecko;  // ignored
+  gfx3DMatrix transformToApzc;
+  gfx3DMatrix transformToGecko;  // ignored
 
   // Convert start and end points to untransformed screen coordinates.
   aTreeManager->GetInputTransforms(aSource, transformToApzc, transformToGecko);
-  Matrix4x4 untransformToApzc = transformToApzc;
-  untransformToApzc.Invert();
-  ApplyTransform(&aStartPoint, untransformToApzc);
-  ApplyTransform(&aEndPoint, untransformToApzc);
+  ApplyTransform(&aStartPoint, transformToApzc.Inverse());
+  ApplyTransform(&aEndPoint, transformToApzc.Inverse());
 
   // Convert start and end points to aTarget's transformed screen coordinates.
   aTreeManager->GetInputTransforms(aTarget, transformToApzc, transformToGecko);
   ApplyTransform(&aStartPoint, transformToApzc);
   ApplyTransform(&aEndPoint, transformToApzc);
 }
 
 bool
@@ -1179,37 +1175,34 @@ APZCTreeManager::GetAPZCAtPoint(AsyncPan
   // explained in the comment on GetInputTransforms. This function will recurse with aApzc at L and P, and the
   // comments explain what values are stored in the variables at these two levels. All the comments
   // use standard matrix notation where the leftmost matrix in a multiplication is applied first.
 
   // ancestorUntransform takes points from aApzc's parent APZC's layer coordinates
   // to aApzc's parent layer's layer coordinates.
   // It is OC.Inverse() * NC.Inverse() * MC.Inverse() at recursion level for L,
   //   and RC.Inverse() * QC.Inverse()                at recursion level for P.
-  Matrix4x4 ancestorUntransform = aApzc->GetAncestorTransform();
-  ancestorUntransform.Invert();
+  gfx3DMatrix ancestorUntransform = aApzc->GetAncestorTransform().Inverse();
 
   // Hit testing for this layer takes place in our parent layer coordinates,
   // since the composition bounds (used to initialize the visible rect against
   // which we hit test are in those coordinates).
-  gfxPointH3D hitTestPointForThisLayer = To3DMatrix(ancestorUntransform).ProjectPoint(aHitTestPoint);
+  gfxPointH3D hitTestPointForThisLayer = ancestorUntransform.ProjectPoint(aHitTestPoint);
   APZCTM_LOG("Untransformed %f %f to transient coordinates %f %f for hit-testing APZC %p\n",
            aHitTestPoint.x, aHitTestPoint.y,
            hitTestPointForThisLayer.x, hitTestPointForThisLayer.y, aApzc);
 
   // childUntransform takes points from aApzc's parent APZC's layer coordinates
   // to aApzc's layer coordinates (which are aApzc's children's ParentLayer coordinates).
   // It is OC.Inverse() * NC.Inverse() * MC.Inverse() * LC.Inverse() * LA.Inverse() at L
   //   and RC.Inverse() * QC.Inverse() * PC.Inverse() * PA.Inverse()                at P.
-  Matrix4x4 cssUntransform = aApzc->GetCSSTransform();
-  cssUntransform.Invert();
-  Matrix4x4 asyncUntransform = aApzc->GetCurrentAsyncTransform();
-  asyncUntransform.Invert();
-  Matrix4x4 childUntransform = ancestorUntransform * cssUntransform * asyncUntransform;
-  gfxPointH3D hitTestPointForChildLayers = To3DMatrix(childUntransform).ProjectPoint(aHitTestPoint);
+  gfx3DMatrix childUntransform = ancestorUntransform
+                               * aApzc->GetCSSTransform().Inverse()
+                               * gfx3DMatrix(aApzc->GetCurrentAsyncTransform()).Inverse();
+  gfxPointH3D hitTestPointForChildLayers = childUntransform.ProjectPoint(aHitTestPoint);
   APZCTM_LOG("Untransformed %f %f to layer coordinates %f %f for APZC %p\n",
            aHitTestPoint.x, aHitTestPoint.y,
            hitTestPointForChildLayers.x, hitTestPointForChildLayers.y, aApzc);
 
   AsyncPanZoomController* result = nullptr;
   // This walks the tree in depth-first, reverse order, so that it encounters
   // APZCs front-to-back on the screen.
   if (hitTestPointForChildLayers.HasPositiveWCoord()) {
@@ -1332,58 +1325,48 @@ APZCTreeManager::GetAPZCAtPoint(AsyncPan
    CSS transform and the accumulation of CSS transforms to its parent APZC. So the APZC for
    layer L would store LC and (MC * NC * OC), and the layer P would store PC and (QC * RC).
    The APZC instances track the last dispatched paint request and so are able to calculate LD and
    PD using those internally stored values.
    The APZCs also obviously have LT, LN, PT, and PN, so all of the above transformation combinations
    required can be generated.
  */
 void
-APZCTreeManager::GetInputTransforms(AsyncPanZoomController *aApzc, Matrix4x4& aTransformToApzcOut,
-                                    Matrix4x4& aTransformToGeckoOut)
+APZCTreeManager::GetInputTransforms(AsyncPanZoomController *aApzc, gfx3DMatrix& aTransformToApzcOut,
+                                    gfx3DMatrix& aTransformToGeckoOut)
 {
   MonitorAutoLock lock(mTreeLock);
 
   // The comments below assume there is a chain of layers L..R with L and P having APZC instances as
   // explained in the comment above. This function is called with aApzc at L, and the loop
   // below performs one iteration, where parent is at P. The comments explain what values are stored
   // in the variables at these two levels. All the comments use standard matrix notation where the
   // leftmost matrix in a multiplication is applied first.
 
   // ancestorUntransform is OC.Inverse() * NC.Inverse() * MC.Inverse()
-  Matrix4x4 ancestorUntransform = aApzc->GetAncestorTransform();
-  ancestorUntransform.Invert();
+  gfx3DMatrix ancestorUntransform = aApzc->GetAncestorTransform().Inverse();
   // asyncUntransform is LA.Inverse()
-  Matrix4x4 asyncUntransform = aApzc->GetCurrentAsyncTransform();
-  asyncUntransform.Invert();
+  gfx3DMatrix asyncUntransform = gfx3DMatrix(aApzc->GetCurrentAsyncTransform()).Inverse();
   // nontransientAsyncTransform is LN
-  Matrix4x4 nontransientAsyncTransform = aApzc->GetNontransientAsyncTransform();
+  gfx3DMatrix nontransientAsyncTransform = aApzc->GetNontransientAsyncTransform();
   // transientAsyncUntransform is LT.Inverse()
-  Matrix4x4 transientAsyncUntransform = nontransientAsyncTransform * asyncUntransform;
+  gfx3DMatrix transientAsyncUntransform = nontransientAsyncTransform * asyncUntransform;
 
   // aTransformToApzcOut is initialized to OC.Inverse() * NC.Inverse() * MC.Inverse() * LC.Inverse() * LN.Inverse()
-  Matrix4x4 cssUntransform = aApzc->GetCSSTransform();
-  cssUntransform.Invert();
-  Matrix4x4 nontransientAsyncUntransform = nontransientAsyncTransform;
-  nontransientAsyncUntransform.Invert();
-  aTransformToApzcOut = ancestorUntransform * cssUntransform * nontransientAsyncUntransform;
+  aTransformToApzcOut = ancestorUntransform * aApzc->GetCSSTransform().Inverse() * nontransientAsyncTransform.Inverse();
   // aTransformToGeckoOut is initialized to LT.Inverse() * LD * LC * MC * NC * OC
   aTransformToGeckoOut = transientAsyncUntransform * aApzc->GetTransformToLastDispatchedPaint() * aApzc->GetCSSTransform() * aApzc->GetAncestorTransform();
 
   for (AsyncPanZoomController* parent = aApzc->GetParent(); parent; parent = parent->GetParent()) {
     // ancestorUntransform is updated to RC.Inverse() * QC.Inverse() when parent == P
-    ancestorUntransform = parent->GetAncestorTransform();
-    ancestorUntransform.Invert();
+    ancestorUntransform = parent->GetAncestorTransform().Inverse();
     // asyncUntransform is updated to PA.Inverse() when parent == P
-    asyncUntransform = parent->GetCurrentAsyncTransform();
-    asyncUntransform.Invert();
+    asyncUntransform = gfx3DMatrix(parent->GetCurrentAsyncTransform()).Inverse();
     // untransformSinceLastApzc is RC.Inverse() * QC.Inverse() * PC.Inverse() * PA.Inverse()
-    cssUntransform = parent->GetCSSTransform();
-    cssUntransform.Invert();
-    Matrix4x4 untransformSinceLastApzc = ancestorUntransform * cssUntransform * asyncUntransform;
+    gfx3DMatrix untransformSinceLastApzc = ancestorUntransform * parent->GetCSSTransform().Inverse() * asyncUntransform;
 
     // aTransformToApzcOut is RC.Inverse() * QC.Inverse() * PC.Inverse() * PA.Inverse() * OC.Inverse() * NC.Inverse() * MC.Inverse() * LC.Inverse() * LN.Inverse()
     aTransformToApzcOut = untransformSinceLastApzc * aTransformToApzcOut;
     // aTransformToGeckoOut is LT.Inverse() * LD * LC * MC * NC * OC * PD * PC * QC * RC
     aTransformToGeckoOut = aTransformToGeckoOut * parent->GetTransformToLastDispatchedPaint() * parent->GetCSSTransform() * parent->GetAncestorTransform();
 
     // The above values for aTransformToApzcOut and aTransformToGeckoOut when parent == P match
     // the required output as explained in the comment above this method. Note that any missing
--- a/gfx/layers/apz/src/APZCTreeManager.h
+++ b/gfx/layers/apz/src/APZCTreeManager.h
@@ -5,27 +5,28 @@
 
 #ifndef mozilla_layers_APZCTreeManager_h
 #define mozilla_layers_APZCTreeManager_h
 
 #include <stdint.h>                     // for uint64_t, uint32_t
 #include "FrameMetrics.h"               // for FrameMetrics, etc
 #include "Units.h"                      // for CSSPoint, CSSRect, etc
 #include "gfxPoint.h"                   // for gfxPoint
+#include "gfx3DMatrix.h"                // for gfx3DMatrix
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT_HELPER2
 #include "mozilla/EventForwards.h"      // for WidgetInputEvent, nsEventStatus
 #include "mozilla/Monitor.h"            // for Monitor
-#include "mozilla/gfx/Matrix.h"         // for Matrix4x4
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "mozilla/Vector.h"             // for mozilla::Vector
 #include "nsTArrayForwardDeclare.h"     // for nsTArray, nsTArray_Impl, etc
 #include "mozilla/gfx/Logging.h"        // for gfx::TreeLog
 
+class gfx3DMatrix;
 class nsIntRegion;
 
 namespace mozilla {
 class InputData;
 class MultiTouchInput;
 
 namespace layers {
 
@@ -321,18 +322,18 @@ public:
      lock the tree of APZCs while they find the right one, and then return an addref'd
      pointer to it. This allows caller code to just use the target APZC without worrying
      about it going away. These are public for testing code and generally should not be
      used by other production code.
   */
   already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScrollableLayerGuid& aGuid);
   already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScreenPoint& aPoint,
                                                          bool* aOutInOverscrolledApzc);
-  void GetInputTransforms(AsyncPanZoomController *aApzc, gfx::Matrix4x4& aTransformToApzcOut,
-                          gfx::Matrix4x4& aTransformToGeckoOut);
+  void GetInputTransforms(AsyncPanZoomController *aApzc, gfx3DMatrix& aTransformToApzcOut,
+                          gfx3DMatrix& aTransformToGeckoOut);
 private:
   /* Helpers */
   AsyncPanZoomController* FindTargetAPZC(AsyncPanZoomController* aApzc, FrameMetrics::ViewID aScrollId);
   AsyncPanZoomController* FindTargetAPZC(AsyncPanZoomController* aApzc, const ScrollableLayerGuid& aGuid);
   AsyncPanZoomController* GetAPZCAtPoint(AsyncPanZoomController* aApzc,
                                          const gfxPoint& aHitTestPoint,
                                          bool* aOutInOverscrolledApzc);
   already_AddRefed<AsyncPanZoomController> CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2);
@@ -352,17 +353,17 @@ private:
    * Note that this means APZCs corresponding to layers at different depths in the tree
    * may end up becoming siblings. It also means that the "root" APZC may have siblings.
    * This function walks the layer tree backwards through siblings and constructs the APZC
    * tree also as a last-child-prev-sibling tree because that simplifies the hit detection
    * code.
    */
   AsyncPanZoomController* UpdatePanZoomControllerTree(CompositorParent* aCompositor,
                                                       Layer* aLayer, uint64_t aLayersId,
-                                                      gfx::Matrix4x4 aTransform,
+                                                      gfx3DMatrix aTransform,
                                                       AsyncPanZoomController* aParent,
                                                       AsyncPanZoomController* aNextSibling,
                                                       bool aIsFirstPaint,
                                                       uint64_t aOriginatingLayersId,
                                                       const APZPaintLogHelper& aPaintLogger,
                                                       nsTArray< nsRefPtr<AsyncPanZoomController> >* aApzcsToDestroy,
                                                       const nsIntRegion& aObscured);
 
@@ -395,17 +396,17 @@ private:
   uint32_t mTouchCount;
   /* The transform from root screen coordinates into mApzcForInputBlock's
    * screen coordinates, as returned through the 'aTransformToApzcOut' parameter
    * of GetInputTransform(), at the start of the input block. This is cached
    * because this transform can change over the course of the input block,
    * but for some operations we need to use the initial transform.
    * Meaningless if mApzcForInputBlock is nullptr.
    */
-  gfx::Matrix4x4 mCachedTransformToApzcForInputBlock;
+  gfx3DMatrix mCachedTransformToApzcForInputBlock;
   /* The chain of APZCs that will handle pans for the current touch input
    * block, in the order in which they will be scrolled. When one APZC has
    * been scrolled as far as it can, any overscroll will be handed off to
    * the next APZC in the chain.
    */
   Vector< nsRefPtr<AsyncPanZoomController> > mOverscrollHandoffChain;
   /* For logging the APZC tree for debugging (enabled by the apz.printtree
    * pref). */
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -124,18 +124,16 @@ WidgetModifiersToDOMModifiers(mozilla::M
 
 }
 
 namespace mozilla {
 namespace layers {
 
 typedef mozilla::layers::AllowedTouchBehavior AllowedTouchBehavior;
 typedef GeckoContentController::APZStateChange APZStateChange;
-typedef mozilla::gfx::Point Point;
-typedef mozilla::gfx::Matrix4x4 Matrix4x4;
 
 /*
  * The following prefs are used to control the behaviour of the APZC.
  * The default values are provided in gfxPrefs.h.
  *
  * "apz.allow-checkerboarding"
  * Pref that allows or disallows checkerboarding
  *
@@ -1289,20 +1287,20 @@ nsEventStatus AsyncPanZoomController::On
   return nsEventStatus_eConsumeNoDefault;
 }
 
 bool
 AsyncPanZoomController::ConvertToGecko(const ScreenPoint& aPoint, CSSPoint* aOut)
 {
   APZCTreeManager* treeManagerLocal = mTreeManager;
   if (treeManagerLocal) {
-    Matrix4x4 transformToApzc;
-    Matrix4x4 transformToGecko;
+    gfx3DMatrix transformToApzc;
+    gfx3DMatrix transformToGecko;
     treeManagerLocal->GetInputTransforms(this, transformToApzc, transformToGecko);
-    Point result = transformToGecko * Point(aPoint.x, aPoint.y);
+    gfxPoint result = transformToGecko.Transform(gfxPoint(aPoint.x, aPoint.y));
     // NOTE: This isn't *quite* LayoutDevicePoint, we just don't have a name
     // for this coordinate space and it maps the closest to LayoutDevicePoint.
     LayoutDevicePoint layoutPoint = LayoutDevicePoint(result.x, result.y);
     { // scoped lock to access mFrameMetrics
       ReentrantMonitorAutoEnter lock(mMonitor);
       *aOut = layoutPoint / mFrameMetrics.mDevPixelsPerCSSPixel;
     }
     return true;
@@ -2296,30 +2294,30 @@ ViewTransform AsyncPanZoomController::Ge
                          * mLastContentPaintMetrics.LayersPixelsPerCSSPixel();
 
   return ViewTransform(-translation,
                        mFrameMetrics.GetZoom()
                      / mLastContentPaintMetrics.mDevPixelsPerCSSPixel
                      / mFrameMetrics.GetParentResolution());
 }
 
-Matrix4x4 AsyncPanZoomController::GetNontransientAsyncTransform() {
+gfx3DMatrix AsyncPanZoomController::GetNontransientAsyncTransform() {
   ReentrantMonitorAutoEnter lock(mMonitor);
-  return Matrix4x4().Scale(mLastContentPaintMetrics.mResolution.scale,
-                           mLastContentPaintMetrics.mResolution.scale,
-                           1.0f);
+  return gfx3DMatrix::ScalingMatrix(mLastContentPaintMetrics.mResolution.scale,
+                                    mLastContentPaintMetrics.mResolution.scale,
+                                    1.0f);
 }
 
-Matrix4x4 AsyncPanZoomController::GetTransformToLastDispatchedPaint() {
+gfx3DMatrix AsyncPanZoomController::GetTransformToLastDispatchedPaint() {
   ReentrantMonitorAutoEnter lock(mMonitor);
   LayerPoint scrollChange = (mLastContentPaintMetrics.GetScrollOffset() - mLastDispatchedPaintMetrics.GetScrollOffset())
                           * mLastContentPaintMetrics.LayersPixelsPerCSSPixel();
   float zoomChange = mLastContentPaintMetrics.GetZoom().scale / mLastDispatchedPaintMetrics.GetZoom().scale;
-  return Matrix4x4().Translate(scrollChange.x, scrollChange.y, 0) *
-         Matrix4x4().Scale(zoomChange, zoomChange, 1);
+  return gfx3DMatrix::Translation(scrollChange.x, scrollChange.y, 0) *
+         gfx3DMatrix::ScalingMatrix(zoomChange, zoomChange, 1);
 }
 
 void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetrics, bool aIsFirstPaint) {
   ReentrantMonitorAutoEnter lock(mMonitor);
   bool isDefault = mFrameMetrics.IsDefault();
 
   mLastContentPaintMetrics = aLayerMetrics;
   UpdateTransformScale();
@@ -2851,22 +2849,22 @@ void AsyncPanZoomController::ShareCompos
         APZC_LOG("%p failed to share FrameMetrics with content process.", this);
       }
     }
   }
 }
 
 ParentLayerPoint AsyncPanZoomController::ToParentLayerCoords(const ScreenPoint& aPoint)
 {
-  return TransformTo<ParentLayerPixel>(To3DMatrix(GetNontransientAsyncTransform() * GetCSSTransform()), aPoint);
+  return TransformTo<ParentLayerPixel>(GetNontransientAsyncTransform() * GetCSSTransform(), aPoint);
 }
 
 void AsyncPanZoomController::UpdateTransformScale()
 {
-  Matrix4x4 nontransientTransforms = GetNontransientAsyncTransform() * GetCSSTransform();
-  if (!FuzzyEqualsMultiplicative(nontransientTransforms._11, nontransientTransforms._22)) {
+  gfx3DMatrix nontransientTransforms = GetNontransientAsyncTransform() * GetCSSTransform();
+  if (!FuzzyEqualsMultiplicative(nontransientTransforms.GetXScale(), nontransientTransforms.GetYScale())) {
     NS_WARNING("The x- and y-scales of the nontransient transforms should be equal");
   }
-  mFrameMetrics.mTransformScale.scale = nontransientTransforms._11;
+  mFrameMetrics.mTransformScale.scale = nontransientTransforms.GetXScale();
 }
 
 }
 }
--- a/gfx/layers/apz/src/AsyncPanZoomController.h
+++ b/gfx/layers/apz/src/AsyncPanZoomController.h
@@ -15,17 +15,17 @@
 #include "mozilla/Monitor.h"
 #include "mozilla/ReentrantMonitor.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/Atomics.h"
 #include "InputData.h"
 #include "Axis.h"
 #include "TaskThrottler.h"
-#include "mozilla/gfx/Matrix.h"
+#include "gfx3DMatrix.h"
 #include "nsRegion.h"
 
 #include "base/message_loop.h"
 
 namespace mozilla {
 
 namespace ipc {
 
@@ -64,17 +64,16 @@ class TouchBlockState;
  * subframes) has its own AsyncPanZoomController. In the future, to support
  * asynchronously scrolled subframes, we want to have one AsyncPanZoomController
  * per frame.
  */
 class AsyncPanZoomController {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AsyncPanZoomController)
 
   typedef mozilla::MonitorAutoLock MonitorAutoLock;
-  typedef mozilla::gfx::Matrix4x4 Matrix4x4;
   typedef uint32_t TouchBehaviorFlags;
 
 public:
   enum GestureBehavior {
     // The platform code is responsible for forwarding gesture events here. We
     // will not attempt to generate gesture events from MultiTouchInputs.
     DEFAULT_GESTURES,
     // An instance of GestureEventListener is used to detect gestures. This is
@@ -217,28 +216,28 @@ public:
    * existing transform, it will make the layer appear with the desired pan/zoom
    * amount.
    */
   ViewTransform GetCurrentAsyncTransform();
 
   /**
    * Returns the part of the async transform that will remain once Gecko does a
    * repaint at the desired metrics. That is, in the steady state:
-   * Matrix4x4(GetCurrentAsyncTransform()) === GetNontransientAsyncTransform()
+   * gfx3DMatrix(GetCurrentAsyncTransform()) === GetNontransientAsyncTransform()
    */
-  Matrix4x4 GetNontransientAsyncTransform();
+  gfx3DMatrix GetNontransientAsyncTransform();
 
   /**
    * Returns the transform to take something from the coordinate space of the
    * last thing we know gecko painted, to the coordinate space of the last thing
    * we asked gecko to paint. In cases where that last request has not yet been
    * processed, this is needed to transform input events properly into a space
    * gecko will understand.
    */
-  Matrix4x4 GetTransformToLastDispatchedPaint();
+  gfx3DMatrix GetTransformToLastDispatchedPaint();
 
   /**
    * Recalculates the displayport. Ideally, this should paint an area bigger
    * than the composite-to dimensions so that when you scroll down, you don't
    * checkerboard immediately. This includes a bunch of logic, including
    * algorithms to bias painting in the direction of the velocity.
    */
   static const LayerMargin CalculatePendingDisplayPort(
@@ -938,29 +937,29 @@ private:
 
 
   /* ===================================================================
    * The functions and members in this section are used to maintain the
    * area that this APZC instance is responsible for. This is used when
    * hit-testing to see which APZC instance should handle touch events.
    */
 public:
-  void SetLayerHitTestData(const nsIntRegion& aRegion, const Matrix4x4& aTransformToLayer,
-                           const Matrix4x4& aTransformForLayer) {
+  void SetLayerHitTestData(const nsIntRegion& aRegion, const gfx3DMatrix& aTransformToLayer,
+                           const gfx3DMatrix& aTransformForLayer) {
     mVisibleRegion = aRegion;
     mAncestorTransform = aTransformToLayer;
     mCSSTransform = aTransformForLayer;
     UpdateTransformScale();
   }
 
-  Matrix4x4 GetAncestorTransform() const {
+  gfx3DMatrix GetAncestorTransform() const {
     return mAncestorTransform;
   }
 
-  Matrix4x4 GetCSSTransform() const {
+  gfx3DMatrix GetCSSTransform() const {
     return mCSSTransform;
   }
 
   bool VisibleRegionContains(const ParentLayerPoint& aPoint) const {
     ParentLayerIntPoint point = RoundedToInt(aPoint);
     return mVisibleRegion.Contains(point.x, point.y);
   }
 
@@ -970,19 +969,19 @@ public:
 
 private:
   /* This is the visible region of the layer that this APZC corresponds to, in
    * that layer's screen pixels (the same coordinate system in which this APZC
    * receives events in ReceiveInputEvent()). */
   nsIntRegion mVisibleRegion;
   /* This is the cumulative CSS transform for all the layers between the parent
    * APZC and this one (not inclusive) */
-  Matrix4x4 mAncestorTransform;
+  gfx3DMatrix mAncestorTransform;
   /* This is the CSS transform for this APZC's layer. */
-  Matrix4x4 mCSSTransform;
+  gfx3DMatrix mCSSTransform;
 
 
   /* ===================================================================
    * The functions and members in this section are used for sharing the
    * FrameMetrics across processes for the progressive tiling code.
    */
 private:
   /* Unique id assigned to each APZC. Used with ViewID to uniquely identify
--- a/gfx/layers/basic/BasicCompositor.cpp
+++ b/gfx/layers/basic/BasicCompositor.cpp
@@ -149,17 +149,17 @@ DrawSurfaceWithTextureCoords(DrawTarget 
   gfx::Rect unitRect(0, 0, 1, 1);
   ExtendMode mode = unitRect.Contains(aTextureCoords) ? ExtendMode::CLAMP : ExtendMode::REPEAT;
 
   FillRectWithMask(aDest, aDestRect, aSource, aFilter, DrawOptions(aOpacity),
                    mode, aMask, aMaskTransform, &matrix);
 }
 
 static pixman_transform
-Matrix4x4ToPixman(const Matrix4x4& aMatrix)
+Matrix3DToPixman(const gfx3DMatrix& aMatrix)
 {
   pixman_f_transform transform;
 
   transform.m[0][0] = aMatrix._11;
   transform.m[0][1] = aMatrix._21;
   transform.m[0][2] = aMatrix._41;
   transform.m[1][0] = aMatrix._12;
   transform.m[1][1] = aMatrix._22;
@@ -172,17 +172,17 @@ Matrix4x4ToPixman(const Matrix4x4& aMatr
   pixman_transform_from_pixman_f_transform(&result, &transform);
 
   return result;
 }
 
 static void
 PixmanTransform(DataSourceSurface* aDest,
                 DataSourceSurface* aSource,
-                const Matrix4x4& aTransform,
+                const gfx3DMatrix& aTransform,
                 const Point& aDestOffset)
 {
   IntSize destSize = aDest->GetSize();
   pixman_image_t* dest = pixman_image_create_bits(PIXMAN_a8r8g8b8,
                                                   destSize.width,
                                                   destSize.height,
                                                   (uint32_t*)aDest->GetData(),
                                                   aDest->Stride());
@@ -191,17 +191,17 @@ PixmanTransform(DataSourceSurface* aDest
   pixman_image_t* src = pixman_image_create_bits(PIXMAN_a8r8g8b8,
                                                  srcSize.width,
                                                  srcSize.height,
                                                  (uint32_t*)aSource->GetData(),
                                                  aSource->Stride());
 
   NS_ABORT_IF_FALSE(src && dest, "Failed to create pixman images?");
 
-  pixman_transform pixTransform = Matrix4x4ToPixman(aTransform);
+  pixman_transform pixTransform = Matrix3DToPixman(aTransform);
   pixman_transform pixTransformInverted;
 
   // If the transform is singular then nothing would be drawn anyway, return here
   if (!pixman_transform_invert(&pixTransformInverted, &pixTransform)) {
     pixman_image_unref(dest);
     pixman_image_unref(src);
     return;
   }
@@ -244,45 +244,46 @@ BasicCompositor::DrawQuad(const gfx::Rec
   // |dest| is a temporary surface.
   RefPtr<DrawTarget> dest = buffer;
 
   buffer->PushClipRect(aClipRect);
   AutoSaveTransform autoSaveTransform(dest);
 
   Matrix newTransform;
   Rect transformBounds;
-  Matrix4x4 new3DTransform;
+  gfx3DMatrix new3DTransform;
   IntPoint offset = mRenderTarget->GetOrigin();
 
   if (aTransform.Is2D()) {
     newTransform = aTransform.As2D();
   } else {
     // Create a temporary surface for the transform.
     dest = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(RoundOut(aRect).Size(), SurfaceFormat::B8G8R8A8);
     if (!dest) {
       return;
     }
 
     Matrix destTransform;
     destTransform.Translate(-aRect.x, -aRect.y);
     dest->SetTransform(destTransform);
 
     // Get the bounds post-transform.
-    new3DTransform = aTransform;
-    Rect transformBounds = new3DTransform.TransformBounds(aRect);
-    transformBounds.IntersectRect(transformBounds, Rect(offset.x, offset.y, buffer->GetSize().width, buffer->GetSize().height));
+    new3DTransform = To3DMatrix(aTransform);
+    gfxRect bounds = new3DTransform.TransformBounds(ThebesRect(aRect));
+    bounds.IntersectRect(bounds, gfxRect(offset.x, offset.y, buffer->GetSize().width, buffer->GetSize().height));
 
+    transformBounds = ToRect(bounds);
     transformBounds.RoundOut();
 
     // Propagate the coordinate offset to our 2D draw target.
     newTransform.Translate(transformBounds.x, transformBounds.y);
 
     // When we apply the 3D transformation, we do it against a temporary
     // surface, so undo the coordinate offset.
-    new3DTransform = Matrix4x4().Translate(aRect.x, aRect.y, 0) * new3DTransform;
+    new3DTransform = gfx3DMatrix::Translation(aRect.x, aRect.y, 0) * new3DTransform;
   }
 
   newTransform.PostTranslate(-offset.x, -offset.y);
   buffer->SetTransform(newTransform);
 
   RefPtr<SourceSurface> sourceMask;
   Matrix maskTransform;
   if (aEffectChain.mSecondaryEffects[EffectTypes::MASK]) {
--- a/gfx/layers/basic/BasicLayerManager.cpp
+++ b/gfx/layers/basic/BasicLayerManager.cpp
@@ -11,16 +11,17 @@
 #include "GeckoProfiler.h"              // for PROFILER_LABEL
 #include "ImageContainer.h"             // for ImageFactory
 #include "Layers.h"                     // for Layer, ContainerLayer, etc
 #include "ReadbackLayer.h"              // for ReadbackLayer
 #include "ReadbackProcessor.h"          // for ReadbackProcessor
 #include "RenderTrace.h"                // for RenderTraceLayers, etc
 #include "basic/BasicImplData.h"        // for BasicImplData
 #include "basic/BasicLayers.h"          // for BasicLayerManager, etc
+#include "gfx3DMatrix.h"                // for gfx3DMatrix
 #include "gfxASurface.h"                // for gfxASurface, etc
 #include "gfxColor.h"                   // for gfxRGBA
 #include "gfxContext.h"                 // for gfxContext, etc
 #include "gfxImageSurface.h"            // for gfxImageSurface
 #include "gfxMatrix.h"                  // for gfxMatrix
 #include "gfxPlatform.h"                // for gfxPlatform
 #include "gfxPrefs.h"                   // for gfxPrefs
 #include "gfxPoint.h"                   // for gfxIntSize, gfxPoint
@@ -603,17 +604,17 @@ BasicLayerManager::SetRoot(Layer* aLayer
 {
   NS_ASSERTION(aLayer, "Root can't be null");
   NS_ASSERTION(aLayer->Manager() == this, "Wrong manager");
   NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
   mRoot = aLayer;
 }
 
 static pixman_transform
-BasicLayerManager_Matrix4x4ToPixman(const Matrix4x4& aMatrix)
+BasicLayerManager_Matrix3DToPixman(const gfx3DMatrix& aMatrix)
 {
   pixman_f_transform transform;
 
   transform.m[0][0] = aMatrix._11;
   transform.m[0][1] = aMatrix._21;
   transform.m[0][2] = aMatrix._41;
   transform.m[1][0] = aMatrix._12;
   transform.m[1][1] = aMatrix._22;
@@ -626,18 +627,18 @@ BasicLayerManager_Matrix4x4ToPixman(cons
   pixman_transform_from_pixman_f_transform(&result, &transform);
 
   return result;
 }
 
 static void
 PixmanTransform(const gfxImageSurface* aDest,
                 RefPtr<DataSourceSurface> aSrc,
-                const Matrix4x4& aTransform,
-                Point aDestOffset)
+                const gfx3DMatrix& aTransform,
+                gfxPoint aDestOffset)
 {
   IntSize destSize = ToIntSize(aDest->GetSize());
   pixman_image_t* dest = pixman_image_create_bits(aDest->Format() == gfxImageFormat::ARGB32 ? PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8,
                                                   destSize.width,
                                                   destSize.height,
                                                   (uint32_t*)aDest->Data(),
                                                   aDest->Stride());
 
@@ -645,17 +646,17 @@ PixmanTransform(const gfxImageSurface* a
   pixman_image_t* src = pixman_image_create_bits(aSrc->GetFormat() == SurfaceFormat::B8G8R8A8 ? PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8,
                                                  srcSize.width,
                                                  srcSize.height,
                                                  (uint32_t*)aSrc->GetData(),
                                                  aSrc->Stride());
 
   NS_ABORT_IF_FALSE(src && dest, "Failed to create pixman images?");
 
-  pixman_transform pixTransform = BasicLayerManager_Matrix4x4ToPixman(aTransform);
+  pixman_transform pixTransform = BasicLayerManager_Matrix3DToPixman(aTransform);
   pixman_transform pixTransformInverted;
 
   // If the transform is singular then nothing would be drawn anyway, return here
   if (!pixman_transform_invert(&pixTransformInverted, &pixTransform)) {
     pixman_image_unref(dest);
     pixman_image_unref(src);
     return;
   }
@@ -674,53 +675,53 @@ PixmanTransform(const gfxImageSurface* a
                            destSize.width,
                            destSize.height);
 
   pixman_image_unref(dest);
   pixman_image_unref(src);
 }
 
 /**
- * Transform a surface using a Matrix4x4 and blit to the destination if
+ * Transform a surface using a gfx3DMatrix and blit to the destination if
  * it is efficient to do so.
  *
  * @param aSource       Source surface.
  * @param aDest         Desintation context.
  * @param aBounds       Area represented by aSource.
  * @param aTransform    Transformation matrix.
  * @param aDestRect     Output: rectangle in which to draw returned surface on aDest
  *                      (same size as aDest). Only filled in if this returns
  *                      a surface.
  * @return              Transformed surface
  */
 static already_AddRefed<gfxASurface>
 Transform3D(RefPtr<SourceSurface> aSource,
             gfxContext* aDest,
-            const Rect& aBounds,
-            const Matrix4x4& aTransform,
-            Rect& aDestRect)
+            const gfxRect& aBounds,
+            const gfx3DMatrix& aTransform,
+            gfxRect& aDestRect)
 {
   // Find the transformed rectangle of our layer.
-  Rect offsetRect = aTransform.TransformBounds(aBounds);
+  gfxRect offsetRect = aTransform.TransformBounds(aBounds);
 
   // Intersect the transformed layer with the destination rectangle.
   // This is in device space since we have an identity transform set on aTarget.
-  aDestRect = ToRect(aDest->GetClipExtents());
+  aDestRect = aDest->GetClipExtents();
   aDestRect.IntersectRect(aDestRect, offsetRect);
   aDestRect.RoundOut();
 
   // Create a surface the size of the transformed object.
   nsRefPtr<gfxASurface> dest = aDest->CurrentSurface();
   nsRefPtr<gfxImageSurface> destImage = new gfxImageSurface(gfxIntSize(aDestRect.width,
                                                                        aDestRect.height),
                                                             gfxImageFormat::ARGB32);
-  Point offset = aDestRect.TopLeft();
+  gfxPoint offset = aDestRect.TopLeft();
 
   // Include a translation to the correct origin.
-  Matrix4x4 translation = Matrix4x4().Translate(aBounds.x, aBounds.y, 0);
+  gfx3DMatrix translation = gfx3DMatrix::Translation(aBounds.x, aBounds.y, 0);
 
   // Transform the content and offset it such that the content begins at the origin.
   PixmanTransform(destImage, aSource->GetDataSurface(), translation * aTransform, offset);
 
   // If we haven't actually drawn to aDest then return our temporary image so
   // that the caller can do this.
   return destImage.forget();
 }
@@ -878,40 +879,41 @@ BasicLayerManager::PaintLayer(gfxContext
                                                       Point(bounds.x, bounds.y));
 
     PaintSelfOrChildren(paintLayerContext, groupTarget);
 
     // Temporary fast fix for bug 725886
     // Revert these changes when 725886 is ready
     NS_ABORT_IF_FALSE(untransformedDT,
                       "We should always allocate an untransformed surface with 3d transforms!");
-    gfx::Rect destRect;
+    gfxRect destRect;
 #ifdef DEBUG
     if (aLayer->GetDebugColorIndex() != 0) {
       gfxRGBA  color((aLayer->GetDebugColorIndex() & 1) ? 1.0 : 0.0,
                      (aLayer->GetDebugColorIndex() & 2) ? 1.0 : 0.0,
                      (aLayer->GetDebugColorIndex() & 4) ? 1.0 : 0.0,
                      1.0);
 
       nsRefPtr<gfxContext> temp = new gfxContext(untransformedDT, Point(bounds.x, bounds.y));
       temp->SetColor(color);
       temp->Paint();
     }
 #endif
+    gfx3DMatrix effectiveTransform = gfx::To3DMatrix(aLayer->GetEffectiveTransform());
     nsRefPtr<gfxASurface> result =
-      Transform3D(untransformedDT->Snapshot(), aTarget, ToRect(bounds),
-                  aLayer->GetEffectiveTransform(), destRect);
+      Transform3D(untransformedDT->Snapshot(), aTarget, bounds,
+                  effectiveTransform, destRect);
 
     if (result) {
-      aTarget->SetSource(result, ThebesPoint(destRect.TopLeft()));
+      aTarget->SetSource(result, destRect.TopLeft());
       // Azure doesn't support EXTEND_NONE, so to avoid extending the edges
       // of the source surface out to the current clip region, clip to
       // the rectangle of the result surface now.
       aTarget->NewPath();
-      aTarget->SnappedRectangle(ThebesRect(destRect));
+      aTarget->SnappedRectangle(destRect);
       aTarget->Clip();
       FlushGroup(paintLayerContext, needsClipToVisibleRegion);
     }
   }
 }
 
 void
 BasicLayerManager::ClearCachedResources(Layer* aSubtree)
--- a/gfx/layers/client/ClientTiledThebesLayer.cpp
+++ b/gfx/layers/client/ClientTiledThebesLayer.cpp
@@ -2,16 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ClientTiledThebesLayer.h"
 #include "FrameMetrics.h"               // for FrameMetrics
 #include "Units.h"                      // for ScreenIntRect, CSSPoint, etc
 #include "UnitTransforms.h"             // for TransformTo
 #include "ClientLayerManager.h"         // for ClientLayerManager, etc
+#include "gfx3DMatrix.h"                // for gfx3DMatrix
 #include "gfxPlatform.h"                // for gfxPlatform
 #include "gfxPrefs.h"                   // for gfxPrefs
 #include "gfxRect.h"                    // for gfxRect
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/gfx/BaseSize.h"       // for BaseSize
 #include "mozilla/gfx/Rect.h"           // for Rect, RectTyped
 #include "mozilla/layers/LayersMessages.h"
 #include "mozilla/mozalloc.h"           // for operator delete, etc
@@ -52,36 +53,36 @@ ClientTiledThebesLayer::ClearCachedResou
 
 void
 ClientTiledThebesLayer::FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
 {
   aAttrs = ThebesLayerAttributes(GetValidRegion());
 }
 
 static LayerRect
-ApplyParentLayerToLayerTransform(const gfx::Matrix4x4& aTransform, const ParentLayerRect& aParentLayerRect)
+ApplyParentLayerToLayerTransform(const gfx3DMatrix& aTransform, const ParentLayerRect& aParentLayerRect)
 {
-  return TransformTo<LayerPixel>(gfx::To3DMatrix(aTransform), aParentLayerRect);
+  return TransformTo<LayerPixel>(aTransform, aParentLayerRect);
 }
 
-static gfx::Matrix4x4
+static gfx3DMatrix
 GetTransformToAncestorsParentLayer(Layer* aStart, Layer* aAncestor)
 {
   gfx::Matrix4x4 transform;
   Layer* ancestorParent = aAncestor->GetParent();
   for (Layer* iter = aStart; iter != ancestorParent; iter = iter->GetParent()) {
     if (iter->AsContainerLayer()) {
       // If the layer has a non-transient async transform then we need to apply it here
       // because it will get applied by the APZ in the compositor as well
       const FrameMetrics& metrics = iter->AsContainerLayer()->GetFrameMetrics();
       transform = transform * gfx::Matrix4x4().Scale(metrics.mResolution.scale, metrics.mResolution.scale, 1.f);
     }
     transform = transform * iter->GetTransform();
   }
-  return transform;
+  return gfx::To3DMatrix(transform);
 }
 
 void
 ClientTiledThebesLayer::GetAncestorLayers(ContainerLayer** aOutScrollAncestor,
                                           ContainerLayer** aOutDisplayPortAncestor)
 {
   ContainerLayer* scrollAncestor = nullptr;
   ContainerLayer* displayPortAncestor = nullptr;
@@ -139,19 +140,18 @@ ClientTiledThebesLayer::BeginPaint()
   TILING_LOG("TILING %p: Found scrollAncestor %p and displayPortAncestor %p\n", this,
     scrollAncestor, displayPortAncestor);
 
   const FrameMetrics& scrollMetrics = scrollAncestor->GetFrameMetrics();
   const FrameMetrics& displayportMetrics = displayPortAncestor->GetFrameMetrics();
 
   // Calculate the transform required to convert ParentLayer space of our
   // display port ancestor to the Layer space of this layer.
-  gfx::Matrix4x4 transformDisplayPortToLayer =
-    GetTransformToAncestorsParentLayer(this, displayPortAncestor);
-  transformDisplayPortToLayer.Invert();
+  gfx3DMatrix transformDisplayPortToLayer =
+    GetTransformToAncestorsParentLayer(this, displayPortAncestor).Inverse();
 
   // Note that below we use GetZoomToParent() in a number of places. Because this
   // code runs on the client side, the mTransformScale field of the FrameMetrics
   // will not have been set. This can result in incorrect values being returned
   // by GetZoomToParent() when we have CSS transforms set on some of these layers.
   // This code should be audited and updated as part of fixing bug 993525.
 
   // Compute the critical display port that applies to this layer in the
@@ -166,20 +166,18 @@ ClientTiledThebesLayer::BeginPaint()
   // Store the resolution from the displayport ancestor layer. Because this is Gecko-side,
   // before any async transforms have occurred, we can use the zoom for this.
   mPaintData.mResolution = displayportMetrics.GetZoomToParent();
   TILING_LOG("TILING %p: Resolution %f\n", this, mPaintData.mResolution.scale);
 
   // Store the applicable composition bounds in this layer's Layer units.
   mPaintData.mTransformToCompBounds =
     GetTransformToAncestorsParentLayer(this, scrollAncestor);
-  gfx::Matrix4x4 transformToBounds = mPaintData.mTransformToCompBounds;
-  transformToBounds.Invert();
   mPaintData.mCompositionBounds = ApplyParentLayerToLayerTransform(
-    transformToBounds, scrollMetrics.mCompositionBounds);
+    mPaintData.mTransformToCompBounds.Inverse(), scrollMetrics.mCompositionBounds);
   TILING_LOG("TILING %p: Composition bounds %s\n", this, Stringify(mPaintData.mCompositionBounds).c_str());
 
   // Calculate the scroll offset since the last transaction
   mPaintData.mScrollOffset = displayportMetrics.GetScrollOffset() * displayportMetrics.GetZoomToParent();
   TILING_LOG("TILING %p: Scroll offset %s\n", this, Stringify(mPaintData.mScrollOffset).c_str());
 }
 
 bool
--- a/gfx/layers/client/TiledContentClient.cpp
+++ b/gfx/layers/client/TiledContentClient.cpp
@@ -1077,41 +1077,40 @@ ClientTiledLayerBuffer::ValidateTile(Til
  * basically replaces the nontransient async transform that was injected
  * in GetTransformToAncestorsParentLayer with the complete async transform.
  * This function then returns the scroll ancestor's composition bounds,
  * transformed into the thebes layer's LayerPixel coordinates, accounting
  * for the compositor state.
  */
 static LayerRect
 GetCompositorSideCompositionBounds(ContainerLayer* aScrollAncestor,
-                                   const Matrix4x4& aTransformToCompBounds,
+                                   const gfx3DMatrix& aTransformToCompBounds,
                                    const ViewTransform& aAPZTransform)
 {
-  Matrix4x4 nonTransientAPZUntransform = Matrix4x4().Scale(
+  gfx3DMatrix nonTransientAPZTransform = gfx3DMatrix::ScalingMatrix(
     aScrollAncestor->GetFrameMetrics().mResolution.scale,
     aScrollAncestor->GetFrameMetrics().mResolution.scale,
     1.f);
-  nonTransientAPZUntransform.Invert();
 
-  Matrix4x4 layerTransform = aScrollAncestor->GetTransform();
-  Matrix4x4 layerUntransform = layerTransform;
-  layerUntransform.Invert();
+  gfx3DMatrix layerTransform = gfx::To3DMatrix(aScrollAncestor->GetTransform());
 
   // First take off the last two "terms" of aTransformToCompBounds, which
   // are the scroll ancestor's local transform and the APZ's nontransient async
   // transform.
-  Matrix4x4 transform = aTransformToCompBounds * layerUntransform * nonTransientAPZUntransform;
+  gfx3DMatrix transform = aTransformToCompBounds;
+  transform = transform * layerTransform.Inverse();
+  transform = transform * nonTransientAPZTransform.Inverse();
 
   // Next, apply the APZ's async transform (this includes the nontransient component
   // as well).
-  transform = transform * Matrix4x4(aAPZTransform);
+  transform = transform * gfx3DMatrix(aAPZTransform);
 
   // Finally, put back the scroll ancestor's local transform.
   transform = transform * layerTransform;
-  return TransformTo<LayerPixel>(To3DMatrix(transform).Inverse(),
+  return TransformTo<LayerPixel>(transform.Inverse(),
             aScrollAncestor->GetFrameMetrics().mCompositionBounds);
 }
 
 bool
 ClientTiledLayerBuffer::ComputeProgressiveUpdateRegion(const nsIntRegion& aInvalidRegion,
                                                        const nsIntRegion& aOldValidRegion,
                                                        nsIntRegion& aRegionToPaint,
                                                        BasicTiledLayerPaintData* aPaintData,
--- a/gfx/layers/client/TiledContentClient.h
+++ b/gfx/layers/client/TiledContentClient.h
@@ -7,16 +7,17 @@
 #define MOZILLA_GFX_TILEDCONTENTCLIENT_H
 
 #include <stddef.h>                     // for size_t
 #include <stdint.h>                     // for uint16_t
 #include <algorithm>                    // for swap
 #include "Layers.h"                     // for LayerManager, etc
 #include "TiledLayerBuffer.h"           // for TiledLayerBuffer
 #include "Units.h"                      // for CSSPoint
+#include "gfx3DMatrix.h"                // for gfx3DMatrix
 #include "gfxTypes.h"
 #include "mozilla/Attributes.h"         // for MOZ_OVERRIDE
 #include "mozilla/RefPtr.h"             // for RefPtr
 #include "mozilla/ipc/Shmem.h"          // for Shmem
 #include "mozilla/ipc/SharedMemory.h"   // for SharedMemory
 #include "mozilla/layers/AsyncCompositionManager.h"  // for ViewTransform
 #include "mozilla/layers/CompositableClient.h"  // for CompositableClient
 #include "mozilla/layers/CompositorTypes.h"  // for TextureInfo, etc
@@ -264,17 +265,17 @@ struct BasicTiledLayerPaintData {
   ParentLayerPoint mLastScrollOffset;
 
   /*
    * The transform matrix to go from this layer's Layer units to
    * the scroll ancestor's ParentLayer units. The "scroll ancestor" is
    * the closest ancestor layer which scrolls, and is used to obtain
    * the composition bounds that are relevant for this layer.
    */
-  gfx::Matrix4x4 mTransformToCompBounds;
+  gfx3DMatrix mTransformToCompBounds;
 
   /*
    * The critical displayport of the content from the nearest ancestor layer
    * that represents scrollable content with a display port set. Empty if a
    * critical displayport is not set.
    */
   LayerIntRect mCriticalDisplayPort;
 
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -504,19 +504,19 @@ SampleAnimations(Layer* aLayer, TimeStam
        child = child->GetNextSibling()) {
     activeAnimations |= SampleAnimations(child, aPoint);
   }
 
   return activeAnimations;
 }
 
 Matrix4x4
-AdjustAndCombineWithCSSTransform(const Matrix4x4& asyncTransform, Layer* aLayer)
+AdjustAndCombineWithCSSTransform(const gfx3DMatrix& asyncTransform, Layer* aLayer)
 {
-  Matrix4x4 result = asyncTransform;
+  Matrix4x4 result = ToMatrix4x4(asyncTransform);
 
   // Container layers start at the origin, but they are clipped to where they
   // actually have content on the screen. The tree transform is meant to apply
   // to the clipped area. If the tree transform includes a scale component,
   // then applying it to container as-is will produce incorrect results. To
   // avoid this, translate the layer so that the clip rect starts at the origin,
   // apply the tree transform, and translate back.
   if (const nsIntRect* shadowClipRect = aLayer->AsLayerComposite()->GetShadowClipRect()) {
@@ -670,21 +670,19 @@ ApplyAsyncTransformToScrollbarForContent
     // block accomplishes that and throws away the temp variables.
     // TODO: it might be cleaner to do a pass through the layer tree to advance all the APZC
     // transforms before updating the layer shadow transforms. That will allow removal of this code.
     ViewTransform asyncTransform;
     ScreenPoint scrollOffset;
     apzc->SampleContentTransformForFrame(aCurrentFrame, &asyncTransform, scrollOffset);
   }
 
-  Matrix4x4 asyncTransform = apzc->GetCurrentAsyncTransform();
-  Matrix4x4 nontransientTransform = apzc->GetNontransientAsyncTransform();
-  Matrix4x4 nontransientUntransform = nontransientTransform;
-  nontransientUntransform.Invert();
-  Matrix4x4 transientTransform = asyncTransform * nontransientUntransform;
+  gfx3DMatrix asyncTransform = gfx3DMatrix(apzc->GetCurrentAsyncTransform());
+  gfx3DMatrix nontransientTransform = apzc->GetNontransientAsyncTransform();
+  gfx3DMatrix transientTransform = asyncTransform * nontransientTransform.Inverse();
 
   // |transientTransform| represents the amount by which we have scrolled and
   // zoomed since the last paint. Because the scrollbar was sized and positioned based
   // on the painted content, we need to adjust it based on transientTransform so that
   // it reflects what the user is actually seeing now.
   // - The scroll thumb needs to be scaled in the direction of scrolling by the inverse
   //   of the transientTransform scale (representing the zoom). This is because zooming
   //   in decreases the fraction of the whole scrollable rect that is in view.
@@ -692,35 +690,34 @@ ApplyAsyncTransformToScrollbarForContent
   //   translation (representing the scroll). This is because scrolling down, which
   //   translates the layer content up, should result in moving the scroll thumb down.
   //   The amount of the translation to the scroll thumb should be such that the ratio
   //   of the translation to the size of the scroll port is the same as the ratio
   //   of the scroll amount to the size of the scrollable rect.
   Matrix4x4 scrollbarTransform;
   if (aScrollbar->GetScrollbarDirection() == Layer::VERTICAL) {
     float scale = metrics.CalculateCompositedSizeInCssPixels().height / metrics.mScrollableRect.height;
-    scrollbarTransform = scrollbarTransform * Matrix4x4().Scale(1.f, 1.f / transientTransform._22, 1.f);
+    scrollbarTransform = scrollbarTransform * Matrix4x4().Scale(1.f, 1.f / transientTransform.GetYScale(), 1.f);
     scrollbarTransform = scrollbarTransform * Matrix4x4().Translate(0, -transientTransform._42 * scale, 0);
   }
   if (aScrollbar->GetScrollbarDirection() == Layer::HORIZONTAL) {
     float scale = metrics.CalculateCompositedSizeInCssPixels().width / metrics.mScrollableRect.width;
-    scrollbarTransform = scrollbarTransform * Matrix4x4().Scale(1.f / transientTransform._11, 1.f, 1.f);
+    scrollbarTransform = scrollbarTransform * Matrix4x4().Scale(1.f / transientTransform.GetXScale(), 1.f, 1.f);
     scrollbarTransform = scrollbarTransform * Matrix4x4().Translate(-transientTransform._41 * scale, 0, 0);
   }
 
   Matrix4x4 transform = scrollbarTransform * aScrollbar->GetTransform();
 
   if (aScrollbarIsChild) {
     // If the scrollbar layer is a child of the content it is a scrollbar for, then we
     // need to do an extra untransform to cancel out the transient async transform on
     // the content. This is needed because otherwise that transient async transform is
     // part of the effective transform of this scrollbar, and the scrollbar will jitter
     // as the content scrolls.
-    transientTransform.Invert();
-    transform = transform * transientTransform;
+    transform = transform * ToMatrix4x4(transientTransform.Inverse());
   }
 
   // GetTransform already takes the pre- and post-scale into account.  Since we
   // will apply the pre- and post-scale again when computing the effective
   // transform, we must apply the inverses here.
   transform.Scale(1.0f/aScrollbar->GetPreXScale(),
                   1.0f/aScrollbar->GetPreYScale(),
                   1);
@@ -778,18 +775,21 @@ void
 AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer)
 {
   LayerComposite* layerComposite = aLayer->AsLayerComposite();
   ContainerLayer* container = aLayer->AsContainerLayer();
 
   const FrameMetrics& metrics = container->GetFrameMetrics();
   // We must apply the resolution scale before a pan/zoom transform, so we call
   // GetTransform here.
+  gfx3DMatrix currentTransform = To3DMatrix(aLayer->GetTransform());
   Matrix4x4 oldTransform = aLayer->GetTransform();
 
+  gfx3DMatrix treeTransform;
+
   CSSToLayerScale geckoZoom = metrics.LayersPixelsPerCSSPixel();
 
   LayerIntPoint scrollOffsetLayerPixels = RoundedToInt(metrics.GetScrollOffset() * geckoZoom);
 
   if (mIsFirstPaint) {
     mContentRect = metrics.mScrollableRect;
     SetFirstPaintViewport(scrollOffsetLayerPixels,
                           geckoZoom,
@@ -837,32 +837,32 @@ AsyncCompositionManager::TransformScroll
   LayerToScreenScale zoomAdjust = userZoom / geckoZoom;
 
   LayerPoint geckoScroll(0, 0);
   if (metrics.IsScrollable()) {
     geckoScroll = metrics.GetScrollOffset() * geckoZoom;
   }
 
   LayerPoint translation = (userScroll / zoomAdjust) - geckoScroll;
-  Matrix4x4 treeTransform = ViewTransform(-translation,
+  treeTransform = gfx3DMatrix(ViewTransform(-translation,
                                             userZoom
                                           / metrics.mDevPixelsPerCSSPixel
-                                          / metrics.GetParentResolution());
+                                          / metrics.GetParentResolution()));
 
   // The transform already takes the resolution scale into account.  Since we
   // will apply the resolution scale again when computing the effective
   // transform, we must apply the inverse resolution scale here.
-  Matrix4x4 computedTransform = treeTransform * oldTransform;
+  gfx3DMatrix computedTransform = treeTransform * currentTransform;
   computedTransform.Scale(1.0f/container->GetPreXScale(),
                           1.0f/container->GetPreYScale(),
                           1);
   computedTransform.ScalePost(1.0f/container->GetPostXScale(),
                               1.0f/container->GetPostYScale(),
                               1);
-  layerComposite->SetShadowTransform(computedTransform);
+  layerComposite->SetShadowTransform(ToMatrix4x4(computedTransform));
   NS_ASSERTION(!layerComposite->GetShadowTransformSetByAnimation(),
                "overwriting animated transform!");
 
   // Apply resolution scaling to the old transform - the layer tree as it is
   // doesn't have the necessary transform to display correctly.
   oldTransform.Scale(metrics.mResolution.scale, metrics.mResolution.scale, 1);
 
   // Make sure that overscroll and under-zoom are represented in the old
--- a/gfx/layers/composite/AsyncCompositionManager.h
+++ b/gfx/layers/composite/AsyncCompositionManager.h
@@ -3,22 +3,22 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_ASYNCCOMPOSITIONMANAGER_H
 #define GFX_ASYNCCOMPOSITIONMANAGER_H
 
 #include "Units.h"                      // for LayerPoint, etc
 #include "mozilla/layers/LayerManagerComposite.h"  // for LayerManagerComposite
+#include "gfx3DMatrix.h"                // for gfx3DMatrix
 #include "mozilla/Attributes.h"         // for MOZ_DELETE, MOZ_FINAL, etc
 #include "mozilla/RefPtr.h"             // for RefCounted
 #include "mozilla/TimeStamp.h"          // for TimeStamp
 #include "mozilla/dom/ScreenOrientation.h"  // for ScreenOrientation
 #include "mozilla/gfx/BasePoint.h"      // for BasePoint
-#include "mozilla/gfx/Matrix.h"         // for Matrix4x4
 #include "mozilla/layers/LayersMessages.h"  // for TargetConfig
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsISupportsImpl.h"            // for LayerManager::AddRef, etc
 
 namespace mozilla {
 namespace layers {
 
 class AsyncPanZoomController;
@@ -29,27 +29,27 @@ class AutoResolveRefLayers;
 // Represents (affine) transforms that are calculated from a content view.
 struct ViewTransform {
   ViewTransform(LayerPoint aTranslation = LayerPoint(),
                 ParentLayerToScreenScale aScale = ParentLayerToScreenScale())
     : mTranslation(aTranslation)
     , mScale(aScale)
   {}
 
-  operator gfx::Matrix4x4() const
+  operator gfx3DMatrix() const
   {
     return
-      gfx::Matrix4x4().Translate(mTranslation.x, mTranslation.y, 0) *
-      gfx::Matrix4x4().Scale(mScale.scale, mScale.scale, 1);
+      gfx3DMatrix::Translation(mTranslation.x, mTranslation.y, 0) *
+      gfx3DMatrix::ScalingMatrix(mScale.scale, mScale.scale, 1);
   }
 
   // For convenience, to avoid writing the cumbersome
-  // "gfx::Matrix4x4(a) * gfx::Matrix4x4(b)".
-  friend gfx::Matrix4x4 operator*(const ViewTransform& a, const ViewTransform& b) {
-    return gfx::Matrix4x4(a) * gfx::Matrix4x4(b);
+  // "gfx3dMatrix(a) * gfx3DMatrix(b)".
+  friend gfx3DMatrix operator*(const ViewTransform& a, const ViewTransform& b) {
+    return gfx3DMatrix(a) * gfx3DMatrix(b);
   }
 
   bool operator==(const ViewTransform& rhs) const {
     return mTranslation == rhs.mTranslation && mScale == rhs.mScale;
   }
 
   bool operator!=(const ViewTransform& rhs) const {
     return !(*this == rhs);
--- a/gfx/layers/composite/ContainerLayerComposite.cpp
+++ b/gfx/layers/composite/ContainerLayerComposite.cpp
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ContainerLayerComposite.h"
 #include <algorithm>                    // for min
 #include "FrameMetrics.h"               // for FrameMetrics
 #include "Units.h"                      // for LayerRect, LayerPixel, etc
 #include "gfx2DGlue.h"                  // for ToMatrix4x4
+#include "gfx3DMatrix.h"                // for gfx3DMatrix
 #include "gfxPrefs.h"                   // for gfxPrefs
 #include "gfxUtils.h"                   // for gfxUtils, etc
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/RefPtr.h"             // for RefPtr
 #include "mozilla/UniquePtr.h"          // for UniquePtr
 #include "mozilla/gfx/BaseRect.h"       // for BaseRect
 #include "mozilla/gfx/Matrix.h"         // for Matrix4x4
 #include "mozilla/gfx/Point.h"          // for Point, IntPoint
--- a/gfx/layers/composite/LayerManagerComposite.cpp
+++ b/gfx/layers/composite/LayerManagerComposite.cpp
@@ -17,16 +17,17 @@
 #include "ImageLayerComposite.h"        // for ImageLayerComposite
 #include "Layers.h"                     // for Layer, ContainerLayer, etc
 #include "LayerScope.h"                 // for LayerScope Tool
 #include "protobuf/LayerScopePacket.pb.h" // for protobuf (LayerScope)
 #include "ThebesLayerComposite.h"       // for ThebesLayerComposite
 #include "TiledLayerBuffer.h"           // for TiledLayerComposer
 #include "Units.h"                      // for ScreenIntRect
 #include "gfx2DGlue.h"                  // for ToMatrix4x4
+#include "gfx3DMatrix.h"                // for gfx3DMatrix
 #include "gfxPrefs.h"                   // for gfxPrefs
 #ifdef XP_MACOSX
 #include "gfxPlatformMac.h"
 #endif
 #include "gfxRect.h"                    // for gfxRect
 #include "gfxUtils.h"                   // for frame color util
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/RefPtr.h"             // for RefPtr, TemporaryRef
@@ -558,53 +559,53 @@ LayerManagerComposite::WorldTransformRec
   gfx::Rect grect(aRect.x, aRect.y, aRect.width, aRect.height);
   grect = mWorldMatrix.TransformBounds(grect);
   aRect.SetRect(grect.X(), grect.Y(), grect.Width(), grect.Height());
 }
 
 static void
 SubtractTransformedRegion(nsIntRegion& aRegion,
                           const nsIntRegion& aRegionToSubtract,
-                          const Matrix4x4& aTransform)
+                          const gfx3DMatrix& aTransform)
 {
   if (aRegionToSubtract.IsEmpty()) {
     return;
   }
 
   // For each rect in the region, find out its bounds in screen space and
   // subtract it from the screen region.
   nsIntRegionRectIterator it(aRegionToSubtract);
   while (const nsIntRect* rect = it.Next()) {
-    Rect incompleteRect = aTransform.TransformBounds(ToRect(*rect));
+    gfxRect incompleteRect = aTransform.TransformBounds(gfxRect(*rect));
     aRegion.Sub(aRegion, nsIntRect(incompleteRect.x,
                                    incompleteRect.y,
                                    incompleteRect.width,
                                    incompleteRect.height));
   }
 }
 
 /* static */ void
 LayerManagerComposite::ComputeRenderIntegrityInternal(Layer* aLayer,
                                                       nsIntRegion& aScreenRegion,
                                                       nsIntRegion& aLowPrecisionScreenRegion,
-                                                      const Matrix4x4& aTransform)
+                                                      const gfx3DMatrix& aTransform)
 {
   if (aLayer->GetOpacity() <= 0.f ||
       (aScreenRegion.IsEmpty() && aLowPrecisionScreenRegion.IsEmpty())) {
     return;
   }
 
   // If the layer's a container, recurse into all of its children
   ContainerLayer* container = aLayer->AsContainerLayer();
   if (container) {
     // Accumulate the transform of intermediate surfaces
-    Matrix4x4 transform = aTransform;
+    gfx3DMatrix transform = aTransform;
     if (container->UseIntermediateSurface()) {
-      transform = aLayer->GetEffectiveTransform();
-      transform = aTransform * transform;
+      transform = gfx::To3DMatrix(aLayer->GetEffectiveTransform());
+      transform.PreMultiply(aTransform);
     }
     for (Layer* child = aLayer->GetFirstChild(); child;
          child = child->GetNextSibling()) {
       ComputeRenderIntegrityInternal(child, aScreenRegion, aLowPrecisionScreenRegion, transform);
     }
     return;
   }
 
@@ -615,18 +616,18 @@ LayerManagerComposite::ComputeRenderInte
   }
 
   // See if there's any incomplete rendering
   nsIntRegion incompleteRegion = aLayer->GetEffectiveVisibleRegion();
   incompleteRegion.Sub(incompleteRegion, thebesLayer->GetValidRegion());
 
   if (!incompleteRegion.IsEmpty()) {
     // Calculate the transform to get between screen and layer space
-    Matrix4x4 transformToScreen = aLayer->GetEffectiveTransform();
-    transformToScreen = aTransform * transformToScreen;
+    gfx3DMatrix transformToScreen = To3DMatrix(aLayer->GetEffectiveTransform());
+    transformToScreen.PreMultiply(aTransform);
 
     SubtractTransformedRegion(aScreenRegion, incompleteRegion, transformToScreen);
 
     // See if there's any incomplete low-precision rendering
     TiledLayerComposer* composer = nullptr;
     LayerComposite* shadow = aLayer->AsLayerComposite();
     if (shadow) {
       composer = shadow->GetTiledLayerComposer();
@@ -644,22 +645,24 @@ LayerManagerComposite::ComputeRenderInte
       SubtractTransformedRegion(aLowPrecisionScreenRegion, incompleteRegion, transformToScreen);
     }
   }
 }
 
 #ifdef MOZ_ANDROID_OMTC
 static float
 GetDisplayportCoverage(const CSSRect& aDisplayPort,
-                       const Matrix4x4& aTransformToScreen,
+                       const gfx3DMatrix& aTransformToScreen,
                        const nsIntRect& aScreenRect)
 {
-  Rect transformedDisplayport =
-    aTransformToScreen.TransformBounds(aDisplayPort.ToUnknownRect());
-
+  gfxRect transformedDisplayport =
+    aTransformToScreen.TransformBounds(gfxRect(aDisplayPort.x,
+                                               aDisplayPort.y,
+                                               aDisplayPort.width,
+                                               aDisplayPort.height));
   transformedDisplayport.RoundOut();
   nsIntRect displayport = nsIntRect(transformedDisplayport.x,
                                     transformedDisplayport.y,
                                     transformedDisplayport.width,
                                     transformedDisplayport.height);
   if (!displayport.Contains(aScreenRect)) {
     nsIntRegion coveredRegion;
     coveredRegion.And(aScreenRect, displayport);
@@ -692,25 +695,25 @@ LayerManagerComposite::ComputeRenderInte
 #ifdef MOZ_ANDROID_OMTC
   // Use the transform on the primary scrollable layer and its FrameMetrics
   // to find out how much of the viewport the current displayport covers
   Layer* primaryScrollable = GetPrimaryScrollableLayer();
   if (primaryScrollable) {
     // This is derived from the code in
     // AsyncCompositionManager::TransformScrollableLayer
     const FrameMetrics& metrics = primaryScrollable->AsContainerLayer()->GetFrameMetrics();
-    Matrix4x4 transform = primaryScrollable->GetEffectiveTransform();
+    gfx3DMatrix transform = gfx::To3DMatrix(primaryScrollable->GetEffectiveTransform());
     transform.ScalePost(metrics.mResolution.scale, metrics.mResolution.scale, 1);
 
     // Clip the screen rect to the document bounds
-    Rect documentBounds =
-      transform.TransformBounds(Rect(metrics.mScrollableRect.x - metrics.GetScrollOffset().x,
-                                     metrics.mScrollableRect.y - metrics.GetScrollOffset().y,
-                                     metrics.mScrollableRect.width,
-                                     metrics.mScrollableRect.height));
+    gfxRect documentBounds =
+      transform.TransformBounds(gfxRect(metrics.mScrollableRect.x - metrics.GetScrollOffset().x,
+                                        metrics.mScrollableRect.y - metrics.GetScrollOffset().y,
+                                        metrics.mScrollableRect.width,
+                                        metrics.mScrollableRect.height));
     documentBounds.RoundOut();
     screenRect = screenRect.Intersect(nsIntRect(documentBounds.x, documentBounds.y,
                                                 documentBounds.width, documentBounds.height));
 
     // If the screen rect is empty, the user has scrolled entirely into
     // over-scroll and so we can be considered to have full integrity.
     if (screenRect.IsEmpty()) {
       return 1.0f;
@@ -739,17 +742,17 @@ LayerManagerComposite::ComputeRenderInte
   // If none of the screen is covered, we have zero integrity.
   if (highPrecisionMultiplier <= 0.0f && lowPrecisionMultiplier <= 0.0f) {
     return 0.0f;
   }
 #endif // MOZ_ANDROID_OMTC
 
   nsIntRegion screenRegion(screenRect);
   nsIntRegion lowPrecisionScreenRegion(screenRect);
-  Matrix4x4 transform;
+  gfx3DMatrix transform;
   ComputeRenderIntegrityInternal(root, screenRegion,
                                  lowPrecisionScreenRegion, transform);
 
   if (!screenRegion.IsEqual(screenRect)) {
     // Calculate the area of the region. All rects in an nsRegion are
     // non-overlapping.
     float screenArea = screenRect.width * screenRect.height;
     float highPrecisionIntegrity = screenRegion.Area() / screenArea;
--- a/gfx/layers/composite/LayerManagerComposite.h
+++ b/gfx/layers/composite/LayerManagerComposite.h
@@ -247,17 +247,17 @@ private:
    * Recursive helper method for use by ComputeRenderIntegrity. Subtracts
    * any incomplete rendering on aLayer from aScreenRegion. Any low-precision
    * rendering is included in aLowPrecisionScreenRegion. aTransform is the
    * accumulated transform of intermediate surfaces beneath aLayer.
    */
   static void ComputeRenderIntegrityInternal(Layer* aLayer,
                                              nsIntRegion& aScreenRegion,
                                              nsIntRegion& aLowPrecisionScreenRegion,
-                                             const gfx::Matrix4x4& aTransform);
+                                             const gfx3DMatrix& aTransform);
 
   /**
    * Render the current layer tree to the active target.
    */
   void Render();
 
   /**
    * Render debug overlays such as the FPS/FrameCounter above the frame.
--- a/gfx/layers/ipc/LayerTransactionParent.cpp
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -6,16 +6,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "LayerTransactionParent.h"
 #include <vector>                       // for vector
 #include "CompositableHost.h"           // for CompositableParent, Get, etc
 #include "ImageLayers.h"                // for ImageLayer
 #include "Layers.h"                     // for Layer, ContainerLayer, etc
 #include "ShadowLayerParent.h"          // for ShadowLayerParent
+#include "gfx3DMatrix.h"                // for gfx3DMatrix
 #include "gfxPoint3D.h"                 // for gfxPoint3D
 #include "CompositableTransactionParent.h"  // for EditReplyVector
 #include "ShadowLayersManager.h"        // for ShadowLayersManager
 #include "mozilla/gfx/BasePoint3D.h"    // for BasePoint3D
 #include "mozilla/layers/CanvasLayerComposite.h"
 #include "mozilla/layers/ColorLayerComposite.h"
 #include "mozilla/layers/Compositor.h"  // for Compositor
 #include "mozilla/layers/ContainerLayerComposite.h"
@@ -625,17 +626,17 @@ LayerTransactionParent::RecvGetAnimation
     *aTransform = mozilla::void_t();
     return true;
   }
 
   // The following code recovers the untranslated transform
   // from the shadow transform by undoing the translations in
   // AsyncCompositionManager::SampleValue.
 
-  Matrix4x4 transform = layer->AsLayerComposite()->GetShadowTransform();
+  gfx3DMatrix transform = gfx::To3DMatrix(layer->AsLayerComposite()->GetShadowTransform());
   if (ContainerLayer* c = layer->AsContainerLayer()) {
     // Undo the scale transform applied by AsyncCompositionManager::SampleValue
     transform.ScalePost(1.0f/c->GetInheritedXScale(),
                         1.0f/c->GetInheritedYScale(),
                         1.0f);
   }
   float scale = 1;
   gfxPoint3D scaledOrigin;
@@ -652,22 +653,21 @@ LayerTransactionParent::RecvGetAnimation
         double(nsDeviceContext::AppUnitsPerCSSPixel()) / double(scale);
       transformOrigin = data.transformOrigin() * cssPerDev;
       break;
     }
   }
 
   // Undo the translation to the origin of the reference frame applied by
   // AsyncCompositionManager::SampleValue
-  transform.Translate(-scaledOrigin.x, -scaledOrigin.y, -scaledOrigin.z);
+  transform.Translate(-scaledOrigin);
 
   // Undo the rebasing applied by
   // nsDisplayTransform::GetResultingTransformMatrixInternal
-  gfxPoint3D basis = -scaledOrigin - transformOrigin;
-  transform.ChangeBasis(basis.x, basis.y, basis.z);
+  transform.ChangeBasis(-scaledOrigin - transformOrigin);
 
   // Convert to CSS pixels (this undoes the operations performed by
   // nsStyleTransformMatrix::ProcessTranslatePart which is called from
   // nsDisplayTransform::GetResultingTransformMatrix)
   double devPerCss =
     double(scale) / double(nsDeviceContext::AppUnitsPerCSSPixel());
   transform._41 *= devPerCss;
   transform._42 *= devPerCss;
--- a/gfx/layers/ipc/LayerTransactionParent.h
+++ b/gfx/layers/ipc/LayerTransactionParent.h
@@ -12,16 +12,18 @@
 #include <stdint.h>                     // for uint64_t, uint32_t
 #include "CompositableTransactionParent.h"
 #include "mozilla/Attributes.h"         // for MOZ_OVERRIDE
 #include "mozilla/ipc/SharedMemory.h"   // for SharedMemory, etc
 #include "mozilla/layers/PLayerTransactionParent.h"
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsTArrayForwardDeclare.h"     // for InfallibleTArray
 
+class gfx3DMatrix;
+
 namespace mozilla {
 
 namespace ipc {
 class Shmem;
 }
 
 namespace layout {
 class RenderFrameParent;
--- a/gfx/layers/ipc/LayersMessages.ipdlh
+++ b/gfx/layers/ipc/LayersMessages.ipdlh
@@ -15,16 +15,17 @@ include protocol PTexture;
 include "gfxipc/ShadowLayerUtils.h";
 include "mozilla/GfxMessageUtils.h";
 include "ImageLayers.h";
 
 using mozilla::GraphicsFilterType from "mozilla/GfxMessageUtils.h";
 using struct gfxRGBA from "gfxColor.h";
 using struct gfxPoint3D from "gfxPoint3D.h";
 using class mozilla::gfx::Matrix4x4 from "mozilla/gfx/Matrix.h";
+using class gfx3DMatrix from "gfx3DMatrix.h";
 using nscoord from "nsCoord.h";
 using struct nsIntPoint from "nsPoint.h";
 using struct nsRect from "nsRect.h";
 using struct nsPoint from "nsPoint.h";
 using class mozilla::TimeDuration from "mozilla/TimeStamp.h";
 using class mozilla::TimeStamp from "mozilla/TimeStamp.h";
 using mozilla::ScreenRotation from "mozilla/WidgetUtils.h";
 using nsCSSProperty from "nsCSSProperty.h";
@@ -145,17 +146,17 @@ struct AnimationSegment {
   Animatable startState;
   Animatable endState;
   float startPortion;
   float endPortion;
   TimingFunction sampleFn;
 };
 
 // Transforms need extra information to correctly convert the list of transform
-// functions to a Matrix4x4 that can be applied directly to the layer.
+// functions to a gfx3DMatrix that can be applied directly to the layer.
 struct TransformData {
   // the origin of the frame being transformed in app units
   nsPoint origin;
   // the transform-origin property for the transform in css pixels
   gfxPoint3D transformOrigin;
   // the perspective-origin property for the transform in css pixels
   gfxPoint3D perspectiveOrigin;
   nsRect bounds;
--- a/gfx/layers/ipc/PLayerTransaction.ipdl
+++ b/gfx/layers/ipc/PLayerTransaction.ipdl
@@ -27,17 +27,17 @@ using class mozilla::layers::APZTestData
  * subtree into its own tree), and atomically updating a published
  * subtree.  ("Atomic" in this sense is wrt painting.)
  */
 
 namespace mozilla {
 namespace layers {
 
 union MaybeTransform {
-  Matrix4x4;
+  gfx3DMatrix;
   void_t;
 };
 
 sync protocol PLayerTransaction {
   manager PRenderFrame or PCompositor;
   manages PLayer;
   manages PCompositable;
   manages PTexture;
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -8,16 +8,17 @@
 #include <stdint.h>                     // for uint32_t, uint8_t
 #include <stdlib.h>                     // for free, malloc
 #include "GLContextProvider.h"          // for GLContextProvider
 #include "GLContext.h"                  // for GLContext
 #include "GLUploadHelpers.h"
 #include "Layers.h"                     // for WriteSnapshotToDumpFile
 #include "LayerScope.h"                 // for LayerScope
 #include "gfx2DGlue.h"                  // for ThebesFilter
+#include "gfx3DMatrix.h"                // for gfx3DMatrix
 #include "gfxCrashReporterUtils.h"      // for ScopedGfxFeatureReporter
 #include "GraphicsFilter.h"             // for GraphicsFilter
 #include "gfxPlatform.h"                // for gfxPlatform
 #include "gfxPrefs.h"                   // for gfxPrefs
 #include "gfxRect.h"                    // for gfxRect
 #include "gfxUtils.h"                   // for NextPowerOfTwo, gfxUtils, etc
 #include "mozilla/ArrayUtils.h"         // for ArrayLength
 #include "mozilla/Preferences.h"        // for Preferences
--- a/gfx/layers/opengl/CompositorOGL.h
+++ b/gfx/layers/opengl/CompositorOGL.h
@@ -30,16 +30,17 @@
 #include "nsTArray.h"                   // for nsAutoTArray, nsTArray, etc
 #include "nsThreadUtils.h"              // for nsRunnable
 #include "nsXULAppAPI.h"                // for XRE_GetProcessType
 #include "nscore.h"                     // for NS_IMETHOD
 #ifdef MOZ_WIDGET_GONK
 #include <ui/GraphicBuffer.h>
 #endif
 
+class gfx3DMatrix;
 class nsIWidget;
 
 namespace mozilla {
 class TimeStamp;
 
 namespace gfx {
 class Matrix4x4;
 }
--- a/gfx/layers/opengl/OGLShaderProgram.h
+++ b/gfx/layers/opengl/OGLShaderProgram.h
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_OGLSHADERPROGRAM_H
 #define GFX_OGLSHADERPROGRAM_H
 
 #include "GLContext.h"                  // for fast inlines of glUniform*
+#include "gfx3DMatrix.h"                // for gfx3DMatrix
 #include "gfxTypes.h"
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/RefPtr.h"             // for RefPtr
 #include "mozilla/gfx/Matrix.h"         // for Matrix4x4
 #include "mozilla/gfx/Rect.h"           // for Rect
 #include "mozilla/gfx/Types.h"
 #include "nsDebug.h"                    // for NS_ASSERTION
 #include "nsPoint.h"                    // for nsIntPoint
@@ -465,16 +466,20 @@ protected:
     NS_ASSERTION(aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, "Invalid known uniform");
 
     KnownUniform& ku(mProfile.mUniforms[aKnownUniform]);
     if (ku.UpdateUniform(16, aFloatValues)) {
       mGL->fUniformMatrix4fv(ku.mLocation, 1, false, ku.mValue.f16v);
     }
   }
 
+  void SetMatrixUniform(KnownUniform::KnownUniformName aKnownUniform, const gfx3DMatrix& aMatrix) {
+    SetMatrixUniform(aKnownUniform, &aMatrix._11);
+  }
+
   void SetMatrixUniform(KnownUniform::KnownUniformName aKnownUniform, const gfx::Matrix4x4& aMatrix) {
     SetMatrixUniform(aKnownUniform, &aMatrix._11);
   }
 };
 
 
 } /* layers */
 } /* mozilla */
--- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp
+++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp
@@ -705,19 +705,19 @@ TEST_F(APZCBasicTester, ComplexTransform
   nsRefPtr<TestAsyncPanZoomController> childApzc = new TestAsyncPanZoomController(0, mcc, tm);
 
   const char* layerTreeSyntax = "c(c)";
   // LayerID                     0 1
   nsIntRegion layerVisibleRegion[] = {
     nsIntRegion(nsIntRect(0, 0, 300, 300)),
     nsIntRegion(nsIntRect(0, 0, 150, 300)),
   };
-  Matrix4x4 transforms[] = {
-    Matrix4x4(),
-    Matrix4x4(),
+  gfx3DMatrix transforms[] = {
+    gfx3DMatrix(),
+    gfx3DMatrix(),
   };
   transforms[0].ScalePost(0.5f, 0.5f, 1.0f); // this results from the 2.0 resolution on the root layer
   transforms[1].ScalePost(2.0f, 1.0f, 1.0f); // this is the 2.0 x-axis CSS transform on the child layer
 
   nsTArray<nsRefPtr<Layer> > layers;
   nsRefPtr<LayerManager> lm;
   nsRefPtr<Layer> root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, transforms, lm, layers);
 
@@ -1445,42 +1445,42 @@ CreateTestLayerTree1(nsRefPtr<LayerManag
   // LayerID                     0 1234
   nsIntRegion layerVisibleRegion[] = {
     nsIntRegion(nsIntRect(0,0,100,100)),
     nsIntRegion(nsIntRect(0,0,100,100)),
     nsIntRegion(nsIntRect(10,10,20,20)),
     nsIntRegion(nsIntRect(10,10,20,20)),
     nsIntRegion(nsIntRect(5,5,20,20)),
   };
-  Matrix4x4 transforms[] = {
-    Matrix4x4(),
-    Matrix4x4(),
-    Matrix4x4(),
-    Matrix4x4(),
-    Matrix4x4(),
+  gfx3DMatrix transforms[] = {
+    gfx3DMatrix(),
+    gfx3DMatrix(),
+    gfx3DMatrix(),
+    gfx3DMatrix(),
+    gfx3DMatrix(),
   };
   return CreateLayerTree(layerTreeSyntax, layerVisibleRegion, transforms, aLayerManager, aLayers);
 }
 
 // Layer Tree for HitTesting2
 static already_AddRefed<mozilla::layers::Layer>
 CreateTestLayerTree2(nsRefPtr<LayerManager>& aLayerManager, nsTArray<nsRefPtr<Layer> >& aLayers) {
   const char* layerTreeSyntax = "c(cc(c))";
   // LayerID                     0 12 3
   nsIntRegion layerVisibleRegion[] = {
     nsIntRegion(nsIntRect(0,0,100,100)),
     nsIntRegion(nsIntRect(10,10,40,40)),
     nsIntRegion(nsIntRect(10,60,40,40)),
     nsIntRegion(nsIntRect(10,60,40,40)),
   };
-  Matrix4x4 transforms[] = {
-    Matrix4x4(),
-    Matrix4x4(),
-    Matrix4x4(),
-    Matrix4x4(),
+  gfx3DMatrix transforms[] = {
+    gfx3DMatrix(),
+    gfx3DMatrix(),
+    gfx3DMatrix(),
+    gfx3DMatrix(),
   };
   return CreateLayerTree(layerTreeSyntax, layerVisibleRegion, transforms, aLayerManager, aLayers);
 }
 
 static void
 SetScrollableFrameMetrics(Layer* aLayer, FrameMetrics::ViewID aScrollId,
                           // The scrollable rect is only used in HitTesting2,
                           // HitTesting1 doesn't care about it.
@@ -1494,17 +1494,17 @@ SetScrollableFrameMetrics(Layer* aLayer,
                                                layerBound.width, layerBound.height);
   metrics.mScrollableRect = aScrollableRect;
   metrics.SetScrollOffset(CSSPoint(0, 0));
   container->SetFrameMetrics(metrics);
 }
 
 static already_AddRefed<AsyncPanZoomController>
 GetTargetAPZC(APZCTreeManager* manager, const ScreenPoint& aPoint,
-              Matrix4x4& aTransformToApzcOut, Matrix4x4& aTransformToGeckoOut)
+              gfx3DMatrix& aTransformToApzcOut, gfx3DMatrix& aTransformToGeckoOut)
 {
   nsRefPtr<AsyncPanZoomController> hit = manager->GetTargetAPZC(aPoint, nullptr);
   if (hit) {
     manager->GetInputTransforms(hit.get(), aTransformToApzcOut, aTransformToGeckoOut);
   }
   return hit.forget();
 }
 
@@ -1515,77 +1515,77 @@ TEST_F(APZCTreeManagerTester, HitTesting
   nsRefPtr<Layer> root = CreateTestLayerTree1(lm, layers);
 
   TimeStamp testStartTime = TimeStamp::Now();
   AsyncPanZoomController::SetFrameTime(testStartTime);
   nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
   ScopedLayerTreeRegistration controller(0, root, mcc);
 
   nsRefPtr<APZCTreeManager> manager = new TestAPZCTreeManager();
-  Matrix4x4 transformToApzc;
-  Matrix4x4 transformToGecko;
+  gfx3DMatrix transformToApzc;
+  gfx3DMatrix transformToGecko;
 
   // No APZC attached so hit testing will return no APZC at (20,20)
   nsRefPtr<AsyncPanZoomController> hit = GetTargetAPZC(manager, ScreenPoint(20, 20), transformToApzc, transformToGecko);
   AsyncPanZoomController* nullAPZC = nullptr;
   EXPECT_EQ(nullAPZC, hit.get());
-  EXPECT_EQ(Matrix4x4(), transformToApzc);
-  EXPECT_EQ(Matrix4x4(), transformToGecko);
+  EXPECT_EQ(gfx3DMatrix(), transformToApzc);
+  EXPECT_EQ(gfx3DMatrix(), transformToGecko);
 
   uint32_t paintSequenceNumber = 0;
 
   // Now we have a root APZC that will match the page
   SetScrollableFrameMetrics(root, FrameMetrics::START_SCROLL_ID);
   manager->UpdatePanZoomControllerTree(nullptr, root, false, 0, paintSequenceNumber++);
   hit = GetTargetAPZC(manager, ScreenPoint(15, 15), transformToApzc, transformToGecko);
   EXPECT_EQ(root->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
   // expect hit point at LayerIntPoint(15, 15)
-  EXPECT_EQ(Point(15, 15), transformToApzc * Point(15, 15));
-  EXPECT_EQ(Point(15, 15), transformToGecko * Point(15, 15));
+  EXPECT_EQ(gfxPoint(15, 15), transformToApzc.Transform(gfxPoint(15, 15)));
+  EXPECT_EQ(gfxPoint(15, 15), transformToGecko.Transform(gfxPoint(15, 15)));
 
   // Now we have a sub APZC with a better fit
   SetScrollableFrameMetrics(layers[3], FrameMetrics::START_SCROLL_ID + 1);
   manager->UpdatePanZoomControllerTree(nullptr, root, false, 0, paintSequenceNumber++);
   EXPECT_NE(root->AsContainerLayer()->GetAsyncPanZoomController(), layers[3]->AsContainerLayer()->GetAsyncPanZoomController());
   hit = GetTargetAPZC(manager, ScreenPoint(25, 25), transformToApzc, transformToGecko);
   EXPECT_EQ(layers[3]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
   // expect hit point at LayerIntPoint(25, 25)
-  EXPECT_EQ(Point(25, 25), transformToApzc * Point(25, 25));
-  EXPECT_EQ(Point(25, 25), transformToGecko * Point(25, 25));
+  EXPECT_EQ(gfxPoint(25, 25), transformToApzc.Transform(gfxPoint(25, 25)));
+  EXPECT_EQ(gfxPoint(25, 25), transformToGecko.Transform(gfxPoint(25, 25)));
 
   // At this point, layers[4] obscures layers[3] at the point (15, 15) so
   // hitting there should hit the root APZC
   hit = GetTargetAPZC(manager, ScreenPoint(15, 15), transformToApzc, transformToGecko);
   EXPECT_EQ(root->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
 
   // Now test hit testing when we have two scrollable layers
   SetScrollableFrameMetrics(layers[4], FrameMetrics::START_SCROLL_ID + 2);
   manager->UpdatePanZoomControllerTree(nullptr, root, false, 0, paintSequenceNumber++);
   hit = GetTargetAPZC(manager, ScreenPoint(15, 15), transformToApzc, transformToGecko);
   EXPECT_EQ(layers[4]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
   // expect hit point at LayerIntPoint(15, 15)
-  EXPECT_EQ(Point(15, 15), transformToApzc * Point(15, 15));
-  EXPECT_EQ(Point(15, 15), transformToGecko * Point(15, 15));
+  EXPECT_EQ(gfxPoint(15, 15), transformToApzc.Transform(gfxPoint(15, 15)));
+  EXPECT_EQ(gfxPoint(15, 15), transformToGecko.Transform(gfxPoint(15, 15)));
 
   // Hit test ouside the reach of layer[3,4] but inside root
   hit = GetTargetAPZC(manager, ScreenPoint(90, 90), transformToApzc, transformToGecko);
   EXPECT_EQ(root->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
   // expect hit point at LayerIntPoint(90, 90)
-  EXPECT_EQ(Point(90, 90), transformToApzc * Point(90, 90));
-  EXPECT_EQ(Point(90, 90), transformToGecko * Point(90, 90));
+  EXPECT_EQ(gfxPoint(90, 90), transformToApzc.Transform(gfxPoint(90, 90)));
+  EXPECT_EQ(gfxPoint(90, 90), transformToGecko.Transform(gfxPoint(90, 90)));
 
   // Hit test ouside the reach of any layer
   hit = GetTargetAPZC(manager, ScreenPoint(1000, 10), transformToApzc, transformToGecko);
   EXPECT_EQ(nullAPZC, hit.get());
-  EXPECT_EQ(Matrix4x4(), transformToApzc);
-  EXPECT_EQ(Matrix4x4(), transformToGecko);
+  EXPECT_EQ(gfx3DMatrix(), transformToApzc);
+  EXPECT_EQ(gfx3DMatrix(), transformToGecko);
   hit = GetTargetAPZC(manager, ScreenPoint(-1000, 10), transformToApzc, transformToGecko);
   EXPECT_EQ(nullAPZC, hit.get());
-  EXPECT_EQ(Matrix4x4(), transformToApzc);
-  EXPECT_EQ(Matrix4x4(), transformToGecko);
+  EXPECT_EQ(gfx3DMatrix(), transformToApzc);
+  EXPECT_EQ(gfx3DMatrix(), transformToGecko);
 
   manager->ClearTree();
 }
 
 // A more involved hit testing test that involves css and async transforms.
 TEST_F(APZCTreeManagerTester, HitTesting2) {
   nsTArray<nsRefPtr<Layer> > layers;
   nsRefPtr<LayerManager> lm;
@@ -1593,18 +1593,18 @@ TEST_F(APZCTreeManagerTester, HitTesting
 
   TimeStamp testStartTime = TimeStamp::Now();
   AsyncPanZoomController::SetFrameTime(testStartTime);
   nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
   ScopedLayerTreeRegistration controller(0, root, mcc);
 
   nsRefPtr<TestAPZCTreeManager> manager = new TestAPZCTreeManager();
   nsRefPtr<AsyncPanZoomController> hit;
-  Matrix4x4 transformToApzc;
-  Matrix4x4 transformToGecko;
+  gfx3DMatrix transformToApzc;
+  gfx3DMatrix transformToGecko;
 
   // Set a CSS transform on one of the layers.
   Matrix4x4 transform;
   transform = transform * Matrix4x4().Scale(2, 1, 1);
   layers[2]->SetBaseTransform(transform);
 
   // Make some other layers scrollable.
   SetScrollableFrameMetrics(root, FrameMetrics::START_SCROLL_ID, CSSRect(0, 0, 200, 200));
@@ -1621,53 +1621,53 @@ TEST_F(APZCTreeManagerTester, HitTesting
 
   AsyncPanZoomController* apzcroot = root->AsContainerLayer()->GetAsyncPanZoomController();
   AsyncPanZoomController* apzc1 = layers[1]->AsContainerLayer()->GetAsyncPanZoomController();
   AsyncPanZoomController* apzc3 = layers[3]->AsContainerLayer()->GetAsyncPanZoomController();
 
   // Hit an area that's clearly on the root layer but not any of the child layers.
   hit = GetTargetAPZC(manager, ScreenPoint(75, 25), transformToApzc, transformToGecko);
   EXPECT_EQ(apzcroot, hit.get());
-  EXPECT_EQ(Point(75, 25), transformToApzc * Point(75, 25));
-  EXPECT_EQ(Point(75, 25), transformToGecko * Point(75, 25));
+  EXPECT_EQ(gfxPoint(75, 25), transformToApzc.Transform(gfxPoint(75, 25)));
+  EXPECT_EQ(gfxPoint(75, 25), transformToGecko.Transform(gfxPoint(75, 25)));
 
   // Hit an area on the root that would be on layers[3] if layers[2]
   // weren't transformed.
   // Note that if layers[2] were scrollable, then this would hit layers[2]
   // because its composition bounds would be at (10,60)-(50,100) (and the
   // scale-only transform that we set on layers[2] would be invalid because
   // it would place the layer into overscroll, as its composition bounds
   // start at x=10 but its content at x=20).
   hit = GetTargetAPZC(manager, ScreenPoint(15, 75), transformToApzc, transformToGecko);
   EXPECT_EQ(apzcroot, hit.get());
-  EXPECT_EQ(Point(15, 75), transformToApzc * Point(15, 75));
-  EXPECT_EQ(Point(15, 75), transformToGecko * Point(15, 75));
+  EXPECT_EQ(gfxPoint(15, 75), transformToApzc.Transform(gfxPoint(15, 75)));
+  EXPECT_EQ(gfxPoint(15, 75), transformToGecko.Transform(gfxPoint(15, 75)));
 
   // Hit an area on layers[1].
   hit = GetTargetAPZC(manager, ScreenPoint(25, 25), transformToApzc, transformToGecko);
   EXPECT_EQ(apzc1, hit.get());
-  EXPECT_EQ(Point(25, 25), transformToApzc * Point(25, 25));
-  EXPECT_EQ(Point(25, 25), transformToGecko * Point(25, 25));
+  EXPECT_EQ(gfxPoint(25, 25), transformToApzc.Transform(gfxPoint(25, 25)));
+  EXPECT_EQ(gfxPoint(25, 25), transformToGecko.Transform(gfxPoint(25, 25)));
 
   // Hit an area on layers[3].
   hit = GetTargetAPZC(manager, ScreenPoint(25, 75), transformToApzc, transformToGecko);
   EXPECT_EQ(apzc3, hit.get());
   // transformToApzc should unapply layers[2]'s transform
-  EXPECT_EQ(Point(12.5, 75), transformToApzc * Point(25, 75));
+  EXPECT_EQ(gfxPoint(12.5, 75), transformToApzc.Transform(gfxPoint(25, 75)));
   // and transformToGecko should reapply it
-  EXPECT_EQ(Point(25, 75), transformToGecko * Point(12.5, 75));
+  EXPECT_EQ(gfxPoint(25, 75), transformToGecko.Transform(gfxPoint(12.5, 75)));
 
   // Hit an area on layers[3] that would be on the root if layers[2]
   // weren't transformed.
   hit = GetTargetAPZC(manager, ScreenPoint(75, 75), transformToApzc, transformToGecko);
   EXPECT_EQ(apzc3, hit.get());
   // transformToApzc should unapply layers[2]'s transform
-  EXPECT_EQ(Point(37.5, 75), transformToApzc * Point(75, 75));
+  EXPECT_EQ(gfxPoint(37.5, 75), transformToApzc.Transform(gfxPoint(75, 75)));
   // and transformToGecko should reapply it
-  EXPECT_EQ(Point(75, 75), transformToGecko * Point(37.5, 75));
+  EXPECT_EQ(gfxPoint(75, 75), transformToGecko.Transform(gfxPoint(37.5, 75)));
 
   // Pan the root layer upward by 50 pixels.
   // This causes layers[1] to scroll out of view, and an async transform
   // of -50 to be set on the root layer.
   int time = 0;
   // Silence GMock warnings about "uninteresting mock function calls".
   EXPECT_CALL(*mcc, PostDelayedTask(_,_)).Times(AtLeast(1));
   EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtLeast(1));
@@ -1679,52 +1679,52 @@ TEST_F(APZCTreeManagerTester, HitTesting
   manager->BuildOverscrollHandoffChain(apzcroot);
   ApzcPanNoFling(apzcroot, time, 100, 50);
   manager->ClearOverscrollHandoffChain();
 
   // Hit where layers[3] used to be. It should now hit the root.
   hit = GetTargetAPZC(manager, ScreenPoint(75, 75), transformToApzc, transformToGecko);
   EXPECT_EQ(apzcroot, hit.get());
   // transformToApzc doesn't unapply the root's own async transform
-  EXPECT_EQ(Point(75, 75), transformToApzc * Point(75, 75));
+  EXPECT_EQ(gfxPoint(75, 75), transformToApzc.Transform(gfxPoint(75, 75)));
   // and transformToGecko unapplies it and then reapplies it, because by the
   // time the event being transformed reaches Gecko the new paint request will
   // have been handled.
-  EXPECT_EQ(Point(75, 75), transformToGecko * Point(75, 75));
+  EXPECT_EQ(gfxPoint(75, 75), transformToGecko.Transform(gfxPoint(75, 75)));
 
   // Hit where layers[1] used to be and where layers[3] should now be.
   hit = GetTargetAPZC(manager, ScreenPoint(25, 25), transformToApzc, transformToGecko);
   EXPECT_EQ(apzc3, hit.get());
   // transformToApzc unapplies both layers[2]'s css transform and the root's
   // async transform
-  EXPECT_EQ(Point(12.5, 75), transformToApzc * Point(25, 25));
+  EXPECT_EQ(gfxPoint(12.5, 75), transformToApzc.Transform(gfxPoint(25, 25)));
   // transformToGecko reapplies both the css transform and the async transform
   // because we have already issued a paint request with it.
-  EXPECT_EQ(Point(25, 25), transformToGecko * Point(12.5, 75));
+  EXPECT_EQ(gfxPoint(25, 25), transformToGecko.Transform(gfxPoint(12.5, 75)));
 
   // This second pan will move the APZC by another 50 pixels but since the paint
   // request dispatched above has not "completed", we will not dispatch another
   // one yet. Now we have an async transform on top of the pending paint request
   // transform.
   manager->BuildOverscrollHandoffChain(apzcroot);
   ApzcPanNoFling(apzcroot, time, 100, 50);
   manager->ClearOverscrollHandoffChain();
 
   // Hit where layers[3] used to be. It should now hit the root.
   hit = GetTargetAPZC(manager, ScreenPoint(75, 75), transformToApzc, transformToGecko);
   EXPECT_EQ(apzcroot, hit.get());
   // transformToApzc doesn't unapply the root's own async transform
-  EXPECT_EQ(Point(75, 75), transformToApzc * Point(75, 75));
+  EXPECT_EQ(gfxPoint(75, 75), transformToApzc.Transform(gfxPoint(75, 75)));
   // transformToGecko unapplies the full async transform of -100 pixels, and then
   // reapplies the "D" transform of -50 leading to an overall adjustment of +50
-  EXPECT_EQ(Point(75, 125), transformToGecko * Point(75, 75));
+  EXPECT_EQ(gfxPoint(75, 125), transformToGecko.Transform(gfxPoint(75, 75)));
 
   // Hit where layers[1] used to be. It should now hit the root.
   hit = GetTargetAPZC(manager, ScreenPoint(25, 25), transformToApzc, transformToGecko);
   EXPECT_EQ(apzcroot, hit.get());
   // transformToApzc doesn't unapply the root's own async transform
-  EXPECT_EQ(Point(25, 25), transformToApzc * Point(25, 25));
+  EXPECT_EQ(gfxPoint(25, 25), transformToApzc.Transform(gfxPoint(25, 25)));
   // transformToGecko unapplies the full async transform of -100 pixels, and then
   // reapplies the "D" transform of -50 leading to an overall adjustment of +50
-  EXPECT_EQ(Point(25, 75), transformToGecko * Point(25, 25));
+  EXPECT_EQ(gfxPoint(25, 75), transformToGecko.Transform(gfxPoint(25, 25)));
 
   manager->ClearTree();
 }
--- a/gfx/tests/gtest/TestLayers.cpp
+++ b/gfx/tests/gtest/TestLayers.cpp
@@ -157,17 +157,17 @@ already_AddRefed<Layer> CreateLayer(char
     layer = new TestThebesLayer(aManager);
   }
   return layer.forget();
 }
 
 already_AddRefed<Layer> CreateLayerTree(
     const char* aLayerTreeDescription,
     nsIntRegion* aVisibleRegions,
-    const Matrix4x4* aTransforms,
+    const gfx3DMatrix* aTransforms,
     nsRefPtr<LayerManager>& manager,
     nsTArray<nsRefPtr<Layer> >& aLayersOut) {
 
   aLayersOut.Clear();
 
   manager = new TestLayerManager();
 
   nsRefPtr<Layer> rootLayer = nullptr;
@@ -189,17 +189,17 @@ already_AddRefed<Layer> CreateLayerTree(
       parentContainerLayer = parentContainerLayer->GetParent();
       lastLayer = nullptr;
     } else {
       nsRefPtr<Layer> layer = CreateLayer(aLayerTreeDescription[i], manager.get());
       if (aVisibleRegions) {
         layer->SetVisibleRegion(aVisibleRegions[layerNumber]);
       }
       if (aTransforms) {
-        layer->SetBaseTransform(aTransforms[layerNumber]);
+        layer->SetBaseTransform(ToMatrix4x4(aTransforms[layerNumber]));
       }
       aLayersOut.AppendElement(layer);
       layerNumber++;
       if (rootLayer && !parentContainerLayer) {
         MOZ_CRASH();
       }
       if (!rootLayer) {
         rootLayer = layer;
@@ -220,21 +220,21 @@ already_AddRefed<Layer> CreateLayerTree(
 TEST(Layers, LayerTree) {
   const char* layerTreeSyntax = "c(c(tt))";
   nsIntRegion layerVisibleRegion[] = {
     nsIntRegion(nsIntRect(0,0,100,100)),
     nsIntRegion(nsIntRect(0,0,100,100)),
     nsIntRegion(nsIntRect(0,0,100,100)),
     nsIntRegion(nsIntRect(10,10,20,20)),
   };
-  Matrix4x4 transforms[] = {
-    Matrix4x4(),
-    Matrix4x4(),
-    Matrix4x4(),
-    Matrix4x4(),
+  gfx3DMatrix transforms[] = {
+    gfx3DMatrix(),
+    gfx3DMatrix(),
+    gfx3DMatrix(),
+    gfx3DMatrix(),
   };
   nsTArray<nsRefPtr<Layer> > layers;
 
   nsRefPtr<LayerManager> lm;
   nsRefPtr<Layer> root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, transforms, lm, layers);
 
   // B2G g++ doesn't like ASSERT_NE with nullptr directly. It thinks it's
   // an int.
--- a/gfx/tests/gtest/TestLayers.h
+++ b/gfx/tests/gtest/TestLayers.h
@@ -22,15 +22,15 @@
  *         / \
  *        c   t
  *       / \
  *      t   t
  */
 already_AddRefed<mozilla::layers::Layer> CreateLayerTree(
     const char* aLayerTreeDescription,
     nsIntRegion* aVisibleRegions,
-    const mozilla::gfx::Matrix4x4* aTransforms,
+    const gfx3DMatrix* aTransforms,
     nsRefPtr<mozilla::layers::LayerManager>& aLayerManager,
     nsTArray<nsRefPtr<mozilla::layers::Layer> >& aLayersOut);
 
 
 #endif
 
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -3559,37 +3559,37 @@ static void RestrictScaleToMaxLayerSize(
     aScale.height /= scale;
   }
 }
 static bool
 ChooseScaleAndSetTransform(FrameLayerBuilder* aLayerBuilder,
                            nsDisplayListBuilder* aDisplayListBuilder,
                            nsIFrame* aContainerFrame,
                            const nsRect& aVisibleRect,
-                           const Matrix4x4* aTransform,
+                           const gfx3DMatrix* aTransform,
                            const ContainerLayerParameters& aIncomingScale,
                            ContainerLayer* aLayer,
                            LayerState aState,
                            ContainerLayerParameters& aOutgoingScale)
 {
   nsIntPoint offset;
 
-  Matrix4x4 transform =
-    Matrix4x4().Scale(aIncomingScale.mXScale, aIncomingScale.mYScale, 1.0);
+  gfx3DMatrix transform =
+    gfx3DMatrix::ScalingMatrix(aIncomingScale.mXScale, aIncomingScale.mYScale, 1.0);
   if (aTransform) {
     // aTransform is applied first, then the scale is applied to the result
     transform = (*aTransform)*transform;
     // Set any matrix entries close to integers to be those exact integers.
     // This protects against floating-point inaccuracies causing problems
     // in the checks below.
     // We use the fixed epsilon version here because we don't want the nudging
     // to depend on the scroll position.
     transform.NudgeToIntegersFixedEpsilon();
   }
-  Matrix transform2d;
+  gfxMatrix transform2d;
   if (aContainerFrame &&
       (aState == LAYER_INACTIVE || aState == LAYER_SVG_EFFECTS) &&
       (!aTransform || (aTransform->Is2D(&transform2d) &&
                        !transform2d.HasNonTranslation()))) {
     // When we have an inactive ContainerLayer, translate the container by the offset to the
     // reference frame (and offset all child layers by the reverse) so that the coordinate
     // space of the child layers isn't affected by scrolling.
     // This gets confusing for complicated transform (since we'd have to compute the scale
@@ -3597,17 +3597,17 @@ ChooseScaleAndSetTransform(FrameLayerBui
     // for a css transform would have 0,0 as their offset to the reference frame, so this doesn't
     // matter.
     nsPoint appUnitOffset = aDisplayListBuilder->ToReferenceFrame(aContainerFrame);
     nscoord appUnitsPerDevPixel = aContainerFrame->PresContext()->AppUnitsPerDevPixel();
     offset = nsIntPoint(
         NS_lround(NSAppUnitsToDoublePixels(appUnitOffset.x, appUnitsPerDevPixel)*aIncomingScale.mXScale),
         NS_lround(NSAppUnitsToDoublePixels(appUnitOffset.y, appUnitsPerDevPixel)*aIncomingScale.mYScale));
   }
-  transform = transform * Matrix4x4().Translate(offset.x + aIncomingScale.mOffset.x, offset.y + aIncomingScale.mOffset.y, 0);
+  transform = transform * gfx3DMatrix::Translation(offset.x + aIncomingScale.mOffset.x, offset.y + aIncomingScale.mOffset.y, 0);
 
   if (transform.IsSingular()) {
     return false;
   }
 
   bool canDraw2D = transform.CanDraw2D(&transform2d);
   gfxSize scale;
   // XXX Should we do something for 3D transforms?
@@ -3615,24 +3615,24 @@ ChooseScaleAndSetTransform(FrameLayerBui
     // If the container's transform is animated off main thread, fix a suitable scale size
     // for animation
     if (aContainerFrame->GetContent() &&
         nsLayoutUtils::HasAnimationsForCompositor(
           aContainerFrame->GetContent(), eCSSProperty_transform)) {
       scale = nsLayoutUtils::ComputeSuitableScaleForAnimation(aContainerFrame->GetContent());
     } else {
       // Scale factors are normalized to a power of 2 to reduce the number of resolution changes
-      scale = RoundToFloatPrecision(ThebesMatrix(transform2d).ScaleFactors(true));
+      scale = RoundToFloatPrecision(transform2d.ScaleFactors(true));
       // For frames with a changing transform that's not just a translation,
       // round scale factors up to nearest power-of-2 boundary so that we don't
       // keep having to redraw the content as it scales up and down. Rounding up to nearest
       // power-of-2 boundary ensures we never scale up, only down --- avoiding
       // jaggies. It also ensures we never scale down by more than a factor of 2,
       // avoiding bad downscaling quality.
-      Matrix frameTransform;
+      gfxMatrix frameTransform;
       if (ActiveLayerTracker::IsStyleAnimated(aContainerFrame, eCSSProperty_transform) &&
           aTransform &&
           (!aTransform->Is2D(&frameTransform) || frameTransform.HasNonTranslationOrFlip())) {
         // Don't clamp the scale factor when the new desired scale factor matches the old one
         // or it was previously unscaled.
         bool clamp = true;
         Matrix oldFrameTransform2d;
         if (aLayer->GetBaseTransform().Is2D(&oldFrameTransform2d)) {
@@ -3660,17 +3660,17 @@ ChooseScaleAndSetTransform(FrameLayerBui
     if (aTransform) {
       RestrictScaleToMaxLayerSize(scale, aVisibleRect, aContainerFrame, aLayer);
     }
   } else {
     scale = gfxSize(1.0, 1.0);
   }
 
   // Store the inverse of our resolution-scale on the layer
-  aLayer->SetBaseTransform(transform);
+  aLayer->SetBaseTransform(ToMatrix4x4(transform));
   aLayer->SetPreScale(1.0f/float(scale.width),
                       1.0f/float(scale.height));
   aLayer->SetInheritedScale(aIncomingScale.mXScale,
                             aIncomingScale.mYScale);
 
   aOutgoingScale =
     ContainerLayerParameters(scale.width, scale.height, -offset, aIncomingScale);
   if (aTransform) {
@@ -3723,17 +3723,17 @@ FrameLayerBuilder::RestoreThebesLayerIte
 
 already_AddRefed<ContainerLayer>
 FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder,
                                           LayerManager* aManager,
                                           nsIFrame* aContainerFrame,
                                           nsDisplayItem* aContainerItem,
                                           nsDisplayList* aChildren,
                                           const ContainerLayerParameters& aParameters,
-                                          const Matrix4x4* aTransform,
+                                          const gfx3DMatrix* aTransform,
                                           uint32_t aFlags)
 {
   uint32_t containerDisplayItemKey =
     aContainerItem ? aContainerItem->GetPerFrameKey() : nsDisplayItem::TYPE_ZERO;
   NS_ASSERTION(aContainerFrame, "Container display items here should have a frame");
   NS_ASSERTION(!aContainerItem ||
                aContainerItem->Frame() == aContainerFrame,
                "Container display item must match given frame");
--- a/layout/base/FrameLayerBuilder.h
+++ b/layout/base/FrameLayerBuilder.h
@@ -24,20 +24,16 @@ class nsDisplayItemGeometry;
 namespace mozilla {
 namespace layers {
 class ContainerLayer;
 class LayerManager;
 class BasicLayerManager;
 class ThebesLayer;
 }
 
-namespace gfx {
-class Matrix4x4;
-}
-
 class FrameLayerBuilder;
 class LayerManagerData;
 class ThebesLayerData;
 class ContainerState;
 
 enum LayerState {
   LAYER_NONE,
   LAYER_INACTIVE,
@@ -228,17 +224,17 @@ public:
    */
   already_AddRefed<ContainerLayer>
   BuildContainerLayerFor(nsDisplayListBuilder* aBuilder,
                          LayerManager* aManager,
                          nsIFrame* aContainerFrame,
                          nsDisplayItem* aContainerItem,
                          nsDisplayList* aChildren,
                          const ContainerLayerParameters& aContainerParameters,
-                         const gfx::Matrix4x4* aTransform,
+                         const gfx3DMatrix* aTransform,
                          uint32_t aFlags = 0);
 
   /**
    * Get a retained layer for a display item that needs to create its own
    * layer for rendering (i.e. under nsDisplayItem::BuildLayer). Returns
    * null if no retained layer is available, which usually means that this
    * display item didn't have a layer before so the caller will
    * need to create one.
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -58,18 +58,16 @@
 
 #include <stdint.h>
 #include <algorithm>
 
 using namespace mozilla;
 using namespace mozilla::layers;
 using namespace mozilla::dom;
 using namespace mozilla::layout;
-using namespace mozilla::gfx;
-
 typedef FrameMetrics::ViewID ViewID;
 
 #ifdef DEBUG
 static bool
 SpammyLayoutWarningsEnabled()
 {
   static bool sValue = false;
   static bool sValueInitialized = false;
@@ -4582,17 +4580,17 @@ nsDisplayTransform::GetResultingTransfor
   nsRect bounds = (aBoundsOverride ? *aBoundsOverride :
                    nsDisplayTransform::GetFrameBoundsForTransform(frame));
 
   /* Get the matrix, then change its basis to factor in the origin. */
   bool dummy;
   gfx3DMatrix result;
   // Call IsSVGTransformed() regardless of the value of
   // disp->mSpecifiedTransform, since we still need any transformFromSVGParent.
-  Matrix svgTransform, transformFromSVGParent;
+  mozilla::gfx::Matrix svgTransform, transformFromSVGParent;
   bool hasSVGTransforms =
     frame && frame->IsSVGTransformed(&svgTransform, &transformFromSVGParent);
   /* Transformed frames always have a transform, or are preserving 3d (and might still have perspective!) */
   if (aProperties.mTransformList) {
     result = nsStyleTransformMatrix::ReadTransforms(aProperties.mTransformList->mHead,
                                                     frame ? frame->StyleContext() : nullptr,
                                                     frame ? frame->PresContext() : nullptr,
                                                     dummy, bounds, aAppUnitsPerPixel);
@@ -4742,68 +4740,68 @@ nsDisplayTransform::ShouldPrerenderTrans
     message.Append(')');
     ElementAnimationCollection::LogAsyncAnimationFailure(message,
                                                          aFrame->GetContent());
   }
   return false;
 }
 
 /* If the matrix is singular, or a hidden backface is shown, the frame won't be visible or hit. */
-static bool IsFrameVisible(nsIFrame* aFrame, const Matrix4x4& aMatrix)
+static bool IsFrameVisible(nsIFrame* aFrame, const gfx3DMatrix& aMatrix)
 {
   if (aMatrix.IsSingular()) {
     return false;
   }
   if (aFrame->StyleDisplay()->mBackfaceVisibility == NS_STYLE_BACKFACE_VISIBILITY_HIDDEN &&
       aMatrix.IsBackfaceVisible()) {
     return false;
   }
   return true;
 }
 
-const Matrix4x4&
+const gfx3DMatrix&
 nsDisplayTransform::GetTransform()
 {
   if (mTransform.IsIdentity()) {
     float scale = mFrame->PresContext()->AppUnitsPerDevPixel();
     gfxPoint3D newOrigin =
       gfxPoint3D(NSAppUnitsToFloatPixels(mToReferenceFrame.x, scale),
                  NSAppUnitsToFloatPixels(mToReferenceFrame.y, scale),
                   0.0f);
     if (mTransformGetter) {
       mTransform = mTransformGetter(mFrame, scale);
-      mTransform.ChangeBasis(newOrigin.x, newOrigin.y, newOrigin.z);
+      mTransform.ChangeBasis(newOrigin);
     } else {
       /**
        * Passing true as the final argument means that we want to shift the
        * coordinates to be relative to our reference frame instead of relative
        * to this frame.
        * When we have preserve-3d, our reference frame is already guaranteed
        * to be an ancestor of the preserve-3d chain, so we only need to do
        * this once.
        */
-      mTransform = ToMatrix4x4(
+      mTransform =
         GetResultingTransformMatrix(mFrame, ToReferenceFrame(), scale,
-                                    nullptr, nullptr, true));
+                                    nullptr, nullptr, true);
     }
   }
   return mTransform;
 }
 
 bool
 nsDisplayTransform::ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder)
 {
   return ShouldPrerenderTransformedContent(aBuilder, mFrame, false);
 }
 
 already_AddRefed<Layer> nsDisplayTransform::BuildLayer(nsDisplayListBuilder *aBuilder,
                                                        LayerManager *aManager,
                                                        const ContainerLayerParameters& aContainerParameters)
 {
-  const Matrix4x4& newTransformMatrix = GetTransform();
+  const gfx3DMatrix& newTransformMatrix = GetTransform();
 
   if (mFrame->StyleDisplay()->mBackfaceVisibility == NS_STYLE_BACKFACE_VISIBILITY_HIDDEN &&
       newTransformMatrix.IsBackfaceVisible()) {
     return nullptr;
   }
 
   bool prerender = ShouldPrerenderTransformedContent(aBuilder, mFrame, false);
   uint32_t flags = prerender ?
@@ -4907,32 +4905,32 @@ void nsDisplayTransform::HitTest(nsDispl
    * 1. Get the matrix.  If it's singular, abort (clearly we didn't hit
    *    anything).
    * 2. Invert the matrix.
    * 3. Use it to transform the rect into the correct space.
    * 4. Pass that rect down through to the list's version of HitTest.
    */
   // GetTransform always operates in dev pixels.
   float factor = mFrame->PresContext()->AppUnitsPerDevPixel();
-  Matrix4x4 matrix = GetTransform();
+  gfx3DMatrix matrix = GetTransform();
 
   if (!IsFrameVisible(mFrame, matrix)) {
     return;
   }
 
   /* We want to go from transformed-space to regular space.
    * Thus we have to invert the matrix, which normally does
    * the reverse operation (e.g. regular->transformed)
    */
 
   /* Now, apply the transform and pass it down the channel. */
   nsRect resultingRect;
   if (aRect.width == 1 && aRect.height == 1) {
     // Magic width/height indicating we're hit testing a point, not a rect
-    gfxPointH3D point = To3DMatrix(matrix).Inverse().ProjectPoint(gfxPoint(NSAppUnitsToFloatPixels(aRect.x, factor),
+    gfxPointH3D point = matrix.Inverse().ProjectPoint(gfxPoint(NSAppUnitsToFloatPixels(aRect.x, factor),
                                                                NSAppUnitsToFloatPixels(aRect.y, factor)));
     if (!point.HasPositiveWCoord()) {
       return;
     }
 
     gfxPoint point2d = point.As2DPoint();
 
     resultingRect = nsRect(NSFloatPixelsToAppUnits(float(point2d.x), factor),
@@ -4940,17 +4938,17 @@ void nsDisplayTransform::HitTest(nsDispl
                            1, 1);
 
   } else {
     gfxRect originalRect(NSAppUnitsToFloatPixels(aRect.x, factor),
                          NSAppUnitsToFloatPixels(aRect.y, factor),
                          NSAppUnitsToFloatPixels(aRect.width, factor),
                          NSAppUnitsToFloatPixels(aRect.height, factor));
 
-    gfxRect rect = To3DMatrix(matrix).Inverse().ProjectRectBounds(originalRect);
+    gfxRect rect = matrix.Inverse().ProjectRectBounds(originalRect);
 
     bool snap;
     nsRect childBounds = mStoredList.GetBounds(aBuilder, &snap);
     gfxRect childGfxBounds(NSAppUnitsToFloatPixels(childBounds.x, factor),
                            NSAppUnitsToFloatPixels(childBounds.y, factor),
                            NSAppUnitsToFloatPixels(childBounds.width, factor),
                            NSAppUnitsToFloatPixels(childBounds.height, factor));
     rect = rect.Intersect(childGfxBounds);
@@ -4983,44 +4981,44 @@ void nsDisplayTransform::HitTest(nsDispl
 
 }
 
 float
 nsDisplayTransform::GetHitDepthAtPoint(nsDisplayListBuilder* aBuilder, const nsPoint& aPoint)
 {
   // GetTransform always operates in dev pixels.
   float factor = mFrame->PresContext()->AppUnitsPerDevPixel();
-  Matrix4x4 matrix = GetTransform();
+  gfx3DMatrix matrix = GetTransform();
 
   NS_ASSERTION(IsFrameVisible(mFrame, matrix), "We can't have hit a frame that isn't visible!");
 
-  gfxPointH3D point = To3DMatrix(matrix).Inverse().ProjectPoint(gfxPoint(NSAppUnitsToFloatPixels(aPoint.x, factor),
+  gfxPointH3D point = matrix.Inverse().ProjectPoint(gfxPoint(NSAppUnitsToFloatPixels(aPoint.x, factor),
                                                              NSAppUnitsToFloatPixels(aPoint.y, factor)));
   NS_ASSERTION(point.HasPositiveWCoord(), "Why are we trying to get the depth for a point we didn't hit?");
 
   gfxPoint point2d = point.As2DPoint();
 
-  Point3D transformed = matrix * Point3D(point2d.x, point2d.y, 0);
+  gfxPoint3D transformed = matrix.Transform3D(gfxPoint3D(point2d.x, point2d.y, 0));
   return transformed.z;
 }
 
 /* The bounding rectangle for the object is the overflow rectangle translated
  * by the reference point.
  */
 nsRect nsDisplayTransform::GetBounds(nsDisplayListBuilder *aBuilder, bool* aSnap)
 {
   nsRect untransformedBounds =
     ShouldPrerenderTransformedContent(aBuilder, mFrame) ?
     mFrame->GetVisualOverflowRectRelativeToSelf() :
     mStoredList.GetBounds(aBuilder, aSnap);
   *aSnap = false;
   // GetTransform always operates in dev pixels.
   float factor = mFrame->PresContext()->AppUnitsPerDevPixel();
   return nsLayoutUtils::MatrixTransformRect(untransformedBounds,
-                                            To3DMatrix(GetTransform()),
+                                            GetTransform(),
                                             factor);
 }
 
 /* The transform is opaque iff the transform consists solely of scales and
  * translations and if the underlying content is opaque.  Thus if the transform
  * is of the form
  *
  * |a c e|
@@ -5046,20 +5044,20 @@ nsRegion nsDisplayTransform::GetOpaqueRe
   // covers the entire window, but it allows our transform to be
   // updated extremely cheaply, without invalidating any other
   // content.
   if (ShouldPrerenderTransformedContent(aBuilder, mFrame) ||
       !UntransformVisibleRect(aBuilder, &untransformedVisible)) {
       return nsRegion();
   }
 
-  const Matrix4x4& matrix = GetTransform();
+  const gfx3DMatrix& matrix = GetTransform();
 
   nsRegion result;
-  Matrix matrix2d;
+  gfxMatrix matrix2d;
   bool tmpSnap;
   if (matrix.Is2D(&matrix2d) &&
       matrix2d.PreservesAxisAlignedRectangles() &&
       mStoredList.GetOpaqueRegion(aBuilder, &tmpSnap).Contains(untransformedVisible)) {
     result = mVisibleRect.Intersect(GetBounds(aBuilder, &tmpSnap));
   }
   return result;
 }
@@ -5069,19 +5067,19 @@ nsRegion nsDisplayTransform::GetOpaqueRe
  * works.
  */
 bool nsDisplayTransform::IsUniform(nsDisplayListBuilder *aBuilder, nscolor* aColor)
 {
   nsRect untransformedVisible;
   if (!UntransformVisibleRect(aBuilder, &untransformedVisible)) {
     return false;
   }
-  const Matrix4x4& matrix = GetTransform();
-
-  Matrix matrix2d;
+  const gfx3DMatrix& matrix = GetTransform();
+
+  gfxMatrix matrix2d;
   return matrix.Is2D(&matrix2d) &&
          matrix2d.PreservesAxisAlignedRectangles() &&
          mStoredList.GetVisibleRect().Contains(untransformedVisible) &&
          mStoredList.IsUniform(aBuilder, aColor);
 }
 
 /* If UNIFIED_CONTINUATIONS is defined, we can merge two display lists that
  * share the same underlying content.  Otherwise, doing so results in graphical
@@ -5196,17 +5194,17 @@ bool nsDisplayTransform::UntransformRect
   result = result.Intersect(childGfxBounds);
   *aOutRect = nsLayoutUtils::RoundGfxRectToAppRect(result, factor);
   return true;
 }
 
 bool nsDisplayTransform::UntransformVisibleRect(nsDisplayListBuilder* aBuilder,
                                                 nsRect *aOutRect)
 {
-  const gfx3DMatrix& matrix = To3DMatrix(GetTransform());
+  const gfx3DMatrix& matrix = GetTransform();
   if (matrix.IsSingular())
     return false;
 
   // GetTransform always operates in dev pixels.
   float factor = mFrame->PresContext()->AppUnitsPerDevPixel();
   gfxRect result(NSAppUnitsToFloatPixels(mVisibleRect.x, factor),
                  NSAppUnitsToFloatPixels(mVisibleRect.y, factor),
                  NSAppUnitsToFloatPixels(mVisibleRect.width, factor),
@@ -5228,17 +5226,17 @@ bool nsDisplayTransform::UntransformVisi
   return true;
 }
 
 #ifdef MOZ_DUMP_PAINTING
 void
 nsDisplayTransform::WriteDebugInfo(nsACString& aTo)
 {
   std::stringstream ss;
-  AppendToString(ss, GetTransform());
+  AppendToString(ss, gfx::ToMatrix4x4(GetTransform()));
   aTo += ss.str().c_str();
 }
 #endif
 
 nsDisplaySVGEffects::nsDisplaySVGEffects(nsDisplayListBuilder* aBuilder,
                                          nsIFrame* aFrame, nsDisplayList* aList)
     : nsDisplayWrapList(aBuilder, aFrame, aList),
       mEffectsBounds(aFrame->GetVisualOverflowRectRelativeToSelf())
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -3152,26 +3152,25 @@ private:
  * border box.
  *
  * INVARIANT: The wrapped frame is transformed or we supplied a transform getter
  * function.
  * INVARIANT: The wrapped frame is non-null.
  */ 
 class nsDisplayTransform: public nsDisplayItem
 {
-  typedef mozilla::gfx::Matrix4x4 Matrix4x4;
 public:
   /**
    * Returns a matrix (in pixels) for the current frame. The matrix should be relative to
    * the current frame's coordinate space.
    *
    * @param aFrame The frame to compute the transform for.
    * @param aAppUnitsPerPixel The number of app units per graphics unit.
    */
-  typedef Matrix4x4 (* ComputeTransformFunction)(nsIFrame* aFrame, float aAppUnitsPerPixel);
+  typedef gfx3DMatrix (* ComputeTransformFunction)(nsIFrame* aFrame, float aAppUnitsPerPixel);
 
   /* Constructor accepts a display list, empties it, and wraps it up.  It also
    * ferries the underlying frame to the nsDisplayItem constructor.
    */
   nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame,
                      nsDisplayList *aList, const nsRect& aChildrenVisibleRect,
                      uint32_t aIndex = 0);
   nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame,
@@ -3240,17 +3239,17 @@ public:
   {
     return mChildrenVisibleRect;
   }
 
   enum {
     INDEX_MAX = UINT32_MAX >> nsDisplayItem::TYPE_BITS
   };
 
-  const Matrix4x4& GetTransform();
+  const gfx3DMatrix& GetTransform();
 
   float GetHitDepthAtPoint(nsDisplayListBuilder* aBuilder, const nsPoint& aPoint);
 
   /**
    * TransformRect takes in as parameters a rectangle (in aFrame's coordinate
    * space) and returns the smallest rectangle (in aFrame's coordinate space)
    * containing the transformed image of that rectangle.  That is, it takes
    * the four corners of the rectangle, transforms them according to the
@@ -3379,17 +3378,17 @@ private:
   static gfx3DMatrix GetResultingTransformMatrixInternal(const FrameTransformProperties& aProperties,
                                                          const nsPoint& aOrigin,
                                                          float aAppUnitsPerPixel,
                                                          const nsRect* aBoundsOverride,
                                                          nsIFrame** aOutAncestor,
                                                          bool aOffsetByOrigin);
 
   nsDisplayWrapList mStoredList;
-  Matrix4x4 mTransform;
+  gfx3DMatrix mTransform;
   ComputeTransformFunction mTransformGetter;
   nsRect mChildrenVisibleRect;
   uint32_t mIndex;
 };
 
 /**
  * This class adds basic support for limiting the rendering to the part inside
  * the specified edges.  It's a base class for the display item classes that
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -2411,17 +2411,17 @@ nsLayoutUtils::GetLayerTransformForFrame
 
   nsDisplayListBuilder builder(root, nsDisplayListBuilder::OTHER,
                                false/*don't build caret*/);
   nsDisplayList list;  
   nsDisplayTransform* item =
     new (&builder) nsDisplayTransform(&builder, aFrame, &list, nsRect());
 
   *aTransform =
-    To3DMatrix(item->GetTransform());
+    item->GetTransform();
   item->~nsDisplayTransform();
 
   return true;
 }
 
 static bool
 TransformGfxPointFromAncestor(nsIFrame *aFrame,
                               const gfxPoint &aPoint,
--- a/layout/generic/nsPageFrame.cpp
+++ b/layout/generic/nsPageFrame.cpp
@@ -457,20 +457,20 @@ GetNextPage(nsIFrame* aPageContentFrame)
 }
 
 static void PaintHeaderFooter(nsIFrame* aFrame, nsRenderingContext* aCtx,
                               const nsRect& aDirtyRect, nsPoint aPt)
 {
   static_cast<nsPageFrame*>(aFrame)->PaintHeaderFooter(*aCtx, aPt);
 }
 
-static gfx::Matrix4x4 ComputePageTransform(nsIFrame* aFrame, float aAppUnitsPerPixel)
+static gfx3DMatrix ComputePageTransform(nsIFrame* aFrame, float aAppUnitsPerPixel)
 {
   float scale = aFrame->PresContext()->GetPageScale();
-  return gfx::Matrix4x4().Scale(scale, scale, 1);
+  return gfx3DMatrix::ScalingMatrix(scale, scale, 1);
 }
 
 //------------------------------------------------------------------------------
 void
 nsPageFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                               const nsRect&           aDirtyRect,
                               const nsDisplayListSet& aLists)
 {
--- a/layout/generic/nsSimplePageSequenceFrame.cpp
+++ b/layout/generic/nsSimplePageSequenceFrame.cpp
@@ -761,21 +761,21 @@ nsSimplePageSequenceFrame::DoPageEnd()
 
   ResetPrintCanvasList();
 
   mPageNum++;
   
   return rv;
 }
 
-static gfx::Matrix4x4
+static gfx3DMatrix
 ComputePageSequenceTransform(nsIFrame* aFrame, float aAppUnitsPerPixel)
 {
   float scale = aFrame->PresContext()->GetPrintPreviewScale();
-  return gfx::Matrix4x4().Scale(scale, scale, 1);
+  return gfx3DMatrix::ScalingMatrix(scale, scale, 1);
 }
 
 void
 nsSimplePageSequenceFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                             const nsRect&           aDirtyRect,
                                             const nsDisplayListSet& aLists)
 {
   DisplayBorderBackgroundOutline(aBuilder, aLists);
--- a/layout/ipc/RenderFrameParent.cpp
+++ b/layout/ipc/RenderFrameParent.cpp
@@ -3,16 +3,17 @@
  */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "base/basictypes.h"
 
 #include "BasicLayers.h"
+#include "gfx3DMatrix.h"
 #ifdef MOZ_ENABLE_D3D9_LAYER
 # include "LayerManagerD3D9.h"
 #endif //MOZ_ENABLE_D3D9_LAYER
 #include "mozilla/BrowserElementParent.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/layers/APZCTreeManager.h"
 #include "mozilla/layers/CompositorParent.h"
@@ -25,76 +26,75 @@
 #include "nsViewportFrame.h"
 #include "RenderFrameParent.h"
 #include "mozilla/layers/LayerManagerComposite.h"
 #include "mozilla/layers/CompositorChild.h"
 #include "ClientLayerManager.h"
 
 typedef nsContentView::ViewConfig ViewConfig;
 using namespace mozilla::dom;
-using namespace mozilla::gfx;
 using namespace mozilla::layers;
 
 namespace mozilla {
 namespace layout {
 
 typedef FrameMetrics::ViewID ViewID;
 typedef RenderFrameParent::ViewMap ViewMap;
 
 // Represents (affine) transforms that are calculated from a content view.
 struct ViewTransform {
   ViewTransform(nsIntPoint aTranslation = nsIntPoint(0, 0), float aXScale = 1, float aYScale = 1)
     : mTranslation(aTranslation)
     , mXScale(aXScale)
     , mYScale(aYScale)
   {}
 
-  operator Matrix4x4() const
+  operator gfx3DMatrix() const
   {
     return
-      Matrix4x4().Translate(mTranslation.x, mTranslation.y, 0) *
-      Matrix4x4().Scale(mXScale, mYScale, 1);
+      gfx3DMatrix::Translation(mTranslation.x, mTranslation.y, 0) *
+      gfx3DMatrix::ScalingMatrix(mXScale, mYScale, 1);
   }
 
   nsIntPoint mTranslation;
   float mXScale;
   float mYScale;
 };
 
 // Matrix helpers
 // For our simple purposes, these helpers apply to 2D affine transformations
 // that can be represented by a scale and a translation. This makes the math
 // much easier because we only expect the diagonals and the translation
 // coordinates of the matrix to be non-zero.
 
-static double GetXScale(const Matrix4x4& aTransform)
+static double GetXScale(const gfx3DMatrix& aTransform)
 {
   return aTransform._11;
 }
  
-static double GetYScale(const Matrix4x4& aTransform)
+static double GetYScale(const gfx3DMatrix& aTransform)
 {
   return aTransform._22;
 }
 
-static void Scale(Matrix4x4& aTransform, double aXScale, double aYScale)
+static void Scale(gfx3DMatrix& aTransform, double aXScale, double aYScale)
 {
   aTransform._11 *= aXScale;
   aTransform._22 *= aYScale;
 }
 
-static void ReverseTranslate(Matrix4x4& aTransform, const gfxPoint& aOffset)
+static void ReverseTranslate(gfx3DMatrix& aTransform, const gfxPoint& aOffset)
 {
   aTransform._41 -= aOffset.x;
   aTransform._42 -= aOffset.y;
 }
 
 
 static void ApplyTransform(nsRect& aRect,
-                           Matrix4x4& aTransform,
+                           gfx3DMatrix& aTransform,
                            nscoord auPerDevPixel)
 {
   aRect.x = aRect.x * aTransform._11 + aTransform._41 * auPerDevPixel;
   aRect.y = aRect.y * aTransform._22 + aTransform._42 * auPerDevPixel;
   aRect.width = aRect.width * aTransform._11;
   aRect.height = aRect.height * aTransform._22;
 }
  
@@ -198,61 +198,61 @@ ComputeShadowTreeTransform(nsIFrame* aCo
     return ViewTransform(nsIntPoint(0, 0), 1, 1);
   }
 }
 
 // Use shadow layer tree to build display list for the browser's frame.
 static void
 BuildListForLayer(Layer* aLayer,
                   nsFrameLoader* aRootFrameLoader,
-                  const Matrix4x4& aTransform,
+                  const gfx3DMatrix& aTransform,
                   nsDisplayListBuilder* aBuilder,
                   nsDisplayList& aShadowTree,
                   nsIFrame* aSubdocFrame)
 {
   const FrameMetrics* metrics = GetFrameMetrics(aLayer);
 
-  Matrix4x4 transform;
+  gfx3DMatrix transform;
 
   if (metrics && metrics->IsScrollable()) {
     const ViewID scrollId = metrics->GetScrollId();
 
     // We need to figure out the bounds of the scrollable region using the
     // shadow layer tree from the remote process. The metrics viewport is
     // defined based on all the transformations of its parent layers and
     // the scale of the current layer.
 
     // Calculate transform for this layer.
     nsContentView* view =
       aRootFrameLoader->GetCurrentRemoteFrame()->GetContentView(scrollId);
     // XXX why don't we include aLayer->GetTransform() in the inverse-scale here?
     // This seems wrong, but it doesn't seem to cause bugs!
-    Matrix4x4 applyTransform = ComputeShadowTreeTransform(
+    gfx3DMatrix applyTransform = ComputeShadowTreeTransform(
       aSubdocFrame, aRootFrameLoader, metrics, view->GetViewConfig(),
       1 / GetXScale(aTransform), 1 / GetYScale(aTransform));
-    transform = applyTransform * aLayer->GetTransform() * aTransform;
+    transform = applyTransform * To3DMatrix(aLayer->GetTransform()) * aTransform;
 
     // As mentioned above, bounds calculation also depends on the scale
     // of this layer.
-    Matrix4x4 tmpTransform = aTransform;
+    gfx3DMatrix tmpTransform = aTransform;
     Scale(tmpTransform, GetXScale(applyTransform), GetYScale(applyTransform));
 
     // Calculate rect for this layer based on aTransform.
     nsRect bounds;
     {
       bounds = CSSRect::ToAppUnits(metrics->mViewport);
       nscoord auPerDevPixel = aSubdocFrame->PresContext()->AppUnitsPerDevPixel();
       ApplyTransform(bounds, tmpTransform, auPerDevPixel);
     }
 
     aShadowTree.AppendToTop(
       new (aBuilder) nsDisplayRemoteShadow(aBuilder, aSubdocFrame, bounds, scrollId));
 
   } else {
-    transform = aLayer->GetTransform() * aTransform;
+    transform = To3DMatrix(aLayer->GetTransform()) * aTransform;
   }
 
   for (Layer* child = aLayer->GetFirstChild(); child;
        child = child->GetNextSibling()) {
     BuildListForLayer(child, aRootFrameLoader, transform,
                       aBuilder, aShadowTree, aSubdocFrame);
   }
 }
@@ -267,45 +267,45 @@ TransformShadowTree(nsDisplayListBuilder
 {
   LayerComposite* shadow = aLayer->AsLayerComposite();
   shadow->SetShadowClipRect(aLayer->GetClipRect());
   shadow->SetShadowVisibleRegion(aLayer->GetVisibleRegion());
   shadow->SetShadowOpacity(aLayer->GetOpacity());
 
   const FrameMetrics* metrics = GetFrameMetrics(aLayer);
 
-  Matrix4x4 shadowTransform = aLayer->GetTransform();
+  gfx3DMatrix shadowTransform = To3DMatrix(aLayer->GetTransform());
   ViewTransform layerTransform = aTransform;
 
   if (metrics && metrics->IsScrollable()) {
     const ViewID scrollId = metrics->GetScrollId();
     const nsContentView* view =
       aFrameLoader->GetCurrentRemoteFrame()->GetContentView(scrollId);
     NS_ABORT_IF_FALSE(view, "Array of views should be consistent with layer tree");
-    Matrix4x4 currentTransform = aLayer->GetTransform();
+    gfx3DMatrix currentTransform = To3DMatrix(aLayer->GetTransform());
 
     const ViewConfig& config = view->GetViewConfig();
     // With temporary scale we should compensate translation
     // using temporary scale value
     aTempScaleDiffX *= GetXScale(shadowTransform) * config.mXScale;
     aTempScaleDiffY *= GetYScale(shadowTransform) * config.mYScale;
     ViewTransform viewTransform = ComputeShadowTreeTransform(
       aFrame, aFrameLoader, metrics, view->GetViewConfig(),
       aTempScaleDiffX, aTempScaleDiffY
     );
 
     // Apply the layer's own transform *before* the view transform
-    shadowTransform = Matrix4x4(viewTransform) * currentTransform;
+    shadowTransform = gfx3DMatrix(viewTransform) * currentTransform;
 
     layerTransform = viewTransform;
     if (metrics->IsRootScrollable()) {
       // Apply the translation *before* we do the rest of the transforms.
       nsIntPoint offset = GetContentRectLayerOffset(aFrame, aBuilder);
       shadowTransform = shadowTransform *
-          Matrix4x4().Translate(float(offset.x), float(offset.y), 0.0);
+          gfx3DMatrix::Translation(float(offset.x), float(offset.y), 0.0);
     }
   }
 
   if (aLayer->GetIsFixedPosition() &&
       !aLayer->GetParent()->GetIsFixedPosition()) {
     // Alter the shadow transform of fixed position layers in the situation
     // that the view transform's scroll position doesn't match the actual
     // scroll position, due to asynchronous layer scrolling.
@@ -327,17 +327,17 @@ TransformShadowTree(nsDisplayListBuilder
     shadowTransform.Scale(1.0f/c->GetPreXScale(),
                           1.0f/c->GetPreYScale(),
                           1);
   }
   shadowTransform.ScalePost(1.0f/aLayer->GetPostXScale(),
                             1.0f/aLayer->GetPostYScale(),
                             1);
 
-  shadow->SetShadowTransform(shadowTransform);
+  shadow->SetShadowTransform(gfx::ToMatrix4x4(shadowTransform));
   for (Layer* child = aLayer->GetFirstChild();
        child; child = child->GetNextSibling()) {
     TransformShadowTree(aBuilder, aFrameLoader, aFrame, child, layerTransform,
                         aTempScaleDiffX, aTempScaleDiffY);
   }
 }
 
 static void
@@ -371,17 +371,17 @@ BuildViewMap(ViewMap& oldContentViews, V
              float aXScale = 1, float aYScale = 1,
              float aAccConfigXScale = 1, float aAccConfigYScale = 1)
 {
   ContainerLayer* container = aLayer->AsContainerLayer();
   if (!container)
     return;
   const FrameMetrics metrics = container->GetFrameMetrics();
   const ViewID scrollId = metrics.GetScrollId();
-  Matrix4x4 transform = aLayer->GetTransform();
+  gfx3DMatrix transform = To3DMatrix(aLayer->GetTransform());
   aXScale *= GetXScale(transform);
   aYScale *= GetYScale(transform);
 
   if (metrics.IsScrollable()) {
     nscoord auPerDevPixel = aFrameLoader->GetPrimaryFrameOfOwningContent()
                                         ->PresContext()->AppUnitsPerDevPixel();
     nscoord auPerCSSPixel = auPerDevPixel * metrics.mDevPixelsPerCSSPixel.scale;
     nsContentView* view = FindViewForId(oldContentViews, scrollId);