Make GrMatrix an alias of SkMatrix. Add new methods to SkMatrix.

Review URL: http://codereview.appspot.com/4538043/

Checked in on behalf of reed@ with some additional work (remove the do-nother sk->gr matrix converter).



git-svn-id: http://skia.googlecode.com/svn/trunk@1289 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/include/GrMatrix.h b/gpu/include/GrMatrix.h
index 19a6644..a879ed0 100644
--- a/gpu/include/GrMatrix.h
+++ b/gpu/include/GrMatrix.h
@@ -19,400 +19,8 @@
 #define GrMatrix_DEFINED
 
 #include "GrRect.h"
+#include "SkMatrix.h"
 
-/*
- * 3x3 matrix
- */
-class GrMatrix {
-public:
-    static const GrMatrix& I() {
-        static const GrMatrix I = GrMatrix(GR_Scalar1, 0, 0,
-                                           0, GR_Scalar1, 0,
-                                           0, 0, gRESCALE);
-        return I;
-    };
-    static const GrMatrix& InvalidMatrix() {
-        static const GrMatrix INV = 
-            GrMatrix(GR_ScalarMax, GR_ScalarMax, GR_ScalarMax,
-                     GR_ScalarMax, GR_ScalarMax, GR_ScalarMax,
-                     GR_ScalarMax, GR_ScalarMax, GR_ScalarMax);
-        return INV;
-    }
-    /** 
-     * Handy index constants
-     */
-    enum {
-        kScaleX,
-        kSkewX,
-        kTransX,
-        kSkewY,
-        kScaleY,
-        kTransY,
-        kPersp0,
-        kPersp1,
-        kPersp2
-    };
-    
-    /**
-     * Create an uninitialized matrix
-     */
-    GrMatrix() {
-        fTypeMask = 0;
-    }
-    
-    /**
-     * Create a matrix from an array of values
-     * @param values    row-major array of matrix components
-     */
-    explicit GrMatrix(const GrScalar values[]) {
-        setToArray(values);
-    }
-    
-    /**
-     * Create a matrix from values
-     * @param scaleX    (0,0) matrix element
-     * @param skewX     (0,1) matrix element
-     * @param transX    (0,2) matrix element
-     * @param skewY     (1,0) matrix element
-     * @param scaleY    (1,1) matrix element
-     * @param transY    (1,2) matrix element
-     * @param persp0    (2,0) matrix element
-     * @param persp1    (2,1) matrix element
-     * @param persp2    (2,2) matrix element
-     */
-    GrMatrix(GrScalar scaleX,
-             GrScalar skewX,
-             GrScalar transX,
-             GrScalar skewY,
-             GrScalar scaleY,
-             GrScalar transY,
-             GrScalar persp0,
-             GrScalar persp1,
-             GrScalar persp2) {
-        setAll(scaleX, skewX,  transX,
-               skewY,  scaleY, transY,
-               persp0, persp1, persp2);
-    }
-
-    /**
-     * access matrix component
-     * @return matrix component value
-     */
-    const GrScalar& operator[] (int idx) const {
-        GrAssert((unsigned)idx < 9);
-        return fM[idx];
-    }
-
-    /**
-     * Set a matrix from an array of values
-     * @param values    row-major array of matrix components
-     */
-    void setToArray(const GrScalar values[]) {
-        for (int i = 0; i < 9; ++i) {
-            fM[i] = values[i];
-        }
-        this->computeTypeMask();
-    }
-    
-    /**
-     * Create a matrix from values
-     * @param scaleX    (0,0) matrix element
-     * @param skewX     (0,1) matrix element
-     * @param transX    (0,2) matrix element
-     * @param skewY     (1,0) matrix element
-     * @param scaleY    (1,1) matrix element
-     * @param transY    (1,2) matrix element
-     * @param persp0    (2,0) matrix element
-     * @param persp1    (2,1) matrix element
-     * @param persp2    (2,2) matrix element
-     */
-    void setAll(GrScalar scaleX,
-                GrScalar skewX,
-                GrScalar transX,
-                GrScalar skewY,
-                GrScalar scaleY,
-                GrScalar transY,
-                GrScalar persp0,
-                GrScalar persp1,
-                GrScalar persp2) {
-        fM[kScaleX] = scaleX;
-        fM[kSkewX]  = skewX;
-        fM[kTransX] = transX;
-        fM[kSkewY]  = skewY;
-        fM[kScaleY] = scaleY;
-        fM[kTransY] = transY;
-        fM[kPersp0] = persp0;
-        fM[kPersp1] = persp1;
-        fM[kPersp2] = persp2;
-        
-        this->computeTypeMask();
-    }
-    
-    /**
-     * set matrix component
-     * @param idx    index of component to set
-     * @param value  value to set component to
-     */
-    inline void set(int idx, GrScalar value);
-    
-    /**
-     * make this matrix an identity matrix
-     */
-    void setIdentity();
-
-    /**
-     * overwrite entire matrix to be a translation matrix
-     * @param dx    amount to translate by in x
-     * @param dy    amount to translate by in y
-     */
-    void setTranslate(GrScalar dx, GrScalar dy);
-
-    /**
-     * overwrite entire matrix to be a scaling matrix
-     * @param sx    x scale factor
-     * @param sy    y scale factor
-     */
-    void setScale(GrScalar sx, GrScalar sy);
-
-    /**
-     * overwrite entire matrix to be a skew matrix
-     * @param skx   x skew factor
-     * @param sky   y skew factor
-     */
-    void setSkew(GrScalar skx, GrScalar sky);
-
-    /**
-     * set this matrix to be a concantenation of two
-     * matrices (a*b). Either a, b, or both can be this matrix.
-     * @param a     first matrix to multiply
-     * @param b     second matrix to multiply
-     */
-    void setConcat(const GrMatrix& a, const GrMatrix& b);
-
-    /**
-     * Set this matrix to this*m
-     * @param m     matrix to concatenate
-     */
-    void preConcat(const GrMatrix& m);
-
-    /**
-     * Set this matrix to m*this
-     * @param m     matrix to concatenate
-     */
-    void postConcat(const GrMatrix& m);
-
-    /**
-     *  Compute the inverse of this matrix, and return true if it is invertible,
-     *  or false if not.
-     *
-     *  If inverted is not null, and the matrix is invertible, then the inverse
-     *  is written into it. If the matrix is not invertible (this method returns
-     *  false) then inverted is left unchanged.
-     */
-    bool invert(GrMatrix* inverted) const;
-    
-    /**
-     * Transforms a point by the matrix
-     *
-     * @param src   the point to transform
-     * @return the transformed point
-     */
-    GrPoint mapPoint(const GrPoint& src) const {
-        GrPoint result;
-        (this->*gMapProcs[fTypeMask])(&result, &src, 1);
-        return result;
-    }
-    
-    /**
-     * Transforms an array of points by the matrix.
-     *
-     * @param dstPts the array to write transformed points into
-     * @param srcPts the array of points to transform
-     @ @param count the number of points to transform
-     */
-    void mapPoints(GrPoint dstPts[], 
-                   const GrPoint srcPts[], 
-                   uint32_t count) const {
-        (this->*gMapProcs[fTypeMask])(dstPts, srcPts, count);
-    }
-
-    /**
-     * Transforms pts with arbitrary stride in place.
-     *
-     * @param start  pointer to first point to transform
-     * @param stride distance in bytes between consecutive points
-     @ @param count the number of points to transform
-     */
-    void mapPointsWithStride(GrPoint* start, 
-                             size_t stride, 
-                             uint32_t count) const {
-        for (uint32_t i = 0; i < count; ++i) {            
-            this->mapPoints(start, start, 1);
-            start = (GrPoint*)((intptr_t)start + stride);
-        }
-    }
-
-    /**
-     * Transforms a vector by the matrix. Doesn't handle cases when a
-     * homogeneous vector maps to a point (i.e. perspective transform).
-     * In this case the desired answer is dependent on where the tail of
-     * the vector is in space.
-     */
-    void mapVec(GrVec* vec) {
-        GrAssert(!this->hasPerspective());
-        if (!this->isIdentity()) {
-            GrScalar x = vec->fX;
-            vec->fX = (*this)[kScaleX] * x + (*this)[kSkewX]  * vec->fY;
-            vec->fY = (*this)[kSkewY ] * x + (*this)[kScaleY] * vec->fY;
-        }
-    }
-    
-    /**
-     *  Transform the 4 corners of the src rect, and return the bounding rect
-     *  in the dst rect. Note: src and dst may point to the same memory.
-     */
-    void mapRect(GrRect* dst, const GrRect& src) const;
-
-    /**
-     *  Transform the 4 corners of the rect, and return their bounds in the rect
-     */
-    void mapRect(GrRect* rect) const {
-        this->mapRect(rect, *rect);
-    }
-
-    /**
-     * Checks if matrix is a perspective matrix.
-     * @return true if third row is not (0, 0, 1)
-     */
-    bool hasPerspective() const;
-    
-    /**
-     * Checks whether matrix is identity
-     * @return true if matrix is idenity
-     */
-    bool isIdentity() const;
-
-    /**
-     * Do axis-aligned lines stay axis aligned? May do 90 degree rotation / mirroring.
-     */
-    bool preservesAxisAlignment() const;
-
-    /**
-     * Calculates the maximum stretching factor of the matrix. Only defined if
-     * the matrix does not have perspective.
-     *
-     * @return maximum strecthing factor or negative if matrix has perspective.
-     */
-    GrScalar getMaxStretch() const;
-
-    /**
-     * Checks for matrix equality. Test is element-by-element equality,
-     * not a homogeneous test.
-     * @return true if matrices are equal, false otherwise
-     */
-    bool operator == (const GrMatrix& m) const;
-
-    /**
-     * Checks for matrix inequality. Test is element-by-element inequality,
-     * not a homogeneous test.
-     * @return true if matrices are not equal, false otherwise
-     */
-    bool operator != (const GrMatrix& m) const;
-    
-    static void UnitTest();
-
-private:
-    static const GrScalar gRESCALE;
-
-    void computeTypeMask() {
-        fTypeMask = 0;
-        if (0 != fM[kPersp0] || 0 != fM[kPersp1] || gRESCALE != fM[kPersp2]) {
-            fTypeMask |= kPerspective_TypeBit;
-        }
-        if (GR_Scalar1 != fM[kScaleX] || GR_Scalar1 != fM[kScaleY]) {
-            fTypeMask |= kScale_TypeBit;
-            if (0 == fM[kScaleX] && 0 == fM[kScaleY]) {
-                fTypeMask |= kZeroScale_TypeBit;
-            }
-        }
-        if (0 != fM[kSkewX] || 0 != fM[kSkewY]) {
-            fTypeMask |= kSkew_TypeBit;
-        }
-        if (0 != fM[kTransX] || 0 != fM[kTransY]) {
-            fTypeMask |= kTranslate_TypeBit;
-        }
-    }
-
-    
-    double determinant() const;
-    
-    enum TypeBits {
-        kScale_TypeBit       = 1 << 0, // set if scales are not both 1
-        kTranslate_TypeBit   = 1 << 1, // set if translates are not both 0
-        kSkew_TypeBit        = 1 << 2, // set if skews are not both 0
-        kPerspective_TypeBit = 1 << 3, // set if perspective
-        kZeroScale_TypeBit   = 1 << 4, // set if scales are both zero
-    };
-
-    void mapIdentity(GrPoint* dst, const GrPoint* src, uint32_t count) const;
-    void mapScale(GrPoint* dst, const GrPoint* src, uint32_t count) const;
-    void mapTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const;
-    void mapScaleAndTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const;
-    void mapSkew(GrPoint* dst, const GrPoint* src, uint32_t count) const;
-    void mapScaleAndSkew(GrPoint* dst, const GrPoint* src, uint32_t count) const;
-    void mapSkewAndTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const;
-    void mapNonPerspective(GrPoint* dst, const GrPoint* src, uint32_t count) const;
-    void mapPerspective(GrPoint* dst, const GrPoint* src, uint32_t count) const;
-    void mapZero(GrPoint* dst, const GrPoint* src, uint32_t count) const;
-    void mapSetToTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const;
-    void mapSwappedScale(GrPoint* dst, const GrPoint* src, uint32_t count) const;
-    void mapSwappedScaleAndTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const;
-    
-    void mapInvalid(GrPoint* dst, const GrPoint* src, uint32_t count) const;
-    
-    typedef void (GrMatrix::*MapProc) (GrPoint* dst, const GrPoint* src, uint32_t count) const;
-    static const MapProc gMapProcs[];
-
-    int      fTypeMask;
-    
-    GrScalar fM[9];
-};
-
-void GrMatrix::set(int idx, GrScalar value) {
-    GrAssert((unsigned)idx < 9);
-    fM[idx] = value;
-    if (idx > 5) {
-        if (0 != fM[kPersp0] || 0 != fM[kPersp1] ||
-            gRESCALE != fM[kPersp2]) {
-            fTypeMask |= kPerspective_TypeBit;
-        } else {
-            fTypeMask &= ~kPerspective_TypeBit;
-        }
-    } else if (!(idx % 4)) {
-        if ((GR_Scalar1 == fM[kScaleX] && GR_Scalar1 == fM[kScaleY])) {
-            fTypeMask &= ~kScale_TypeBit;
-            fTypeMask &= ~kZeroScale_TypeBit;
-        } else {
-            fTypeMask |= kScale_TypeBit;
-            if ((0 == fM[kScaleX] && 0 == fM[kScaleY])) {
-                fTypeMask |= kZeroScale_TypeBit;
-            } else {
-                fTypeMask &= ~kZeroScale_TypeBit;
-            }
-        }
-    } else if (2 == (idx % 3)) {
-        if (0 != fM[kTransX] || 0 != fM[kTransY]) {
-            fTypeMask |= kTranslate_TypeBit;
-        } else {
-            fTypeMask &= ~kTranslate_TypeBit;
-        }
-    } else {
-        if (0 != fM[kSkewX] || 0 != fM[kSkewY]) {
-            fTypeMask |= kSkew_TypeBit;
-        } else {
-            fTypeMask &= ~kSkew_TypeBit;
-        }
-    }
-}
+typedef SkMatrix GrMatrix;
 
 #endif
diff --git a/gpu/include/GrTextContext.h b/gpu/include/GrTextContext.h
index a598251..b7a690e 100644
--- a/gpu/include/GrTextContext.h
+++ b/gpu/include/GrTextContext.h
@@ -20,9 +20,9 @@
 
 #include "GrGlyph.h"
 #include "GrPaint.h"
+#include "GrMatrix.h"
 
 struct GrGpuTextVertex;
-class GrMatrix;
 class GrContext;
 class GrTextStrike;
 class GrFontScaler;
diff --git a/gpu/src/GrContext.cpp b/gpu/src/GrContext.cpp
index 8461187..2d93e4b 100644
--- a/gpu/src/GrContext.cpp
+++ b/gpu/src/GrContext.cpp
@@ -925,7 +925,7 @@
             GrVec strokeSize;;
             if (width > 0) {
                 strokeSize.set(width, width);
-                combinedMatrix.mapVec(&strokeSize);
+                combinedMatrix.mapVectors(&strokeSize, 1);
                 strokeSize.setAbs(strokeSize);
             } else {
                 strokeSize.set(GR_Scalar1, GR_Scalar1);
diff --git a/gpu/src/GrGpuGLFixed.cpp b/gpu/src/GrGpuGLFixed.cpp
index dbfac43..e197a82 100644
--- a/gpu/src/GrGpuGLFixed.cpp
+++ b/gpu/src/GrGpuGLFixed.cpp
@@ -32,17 +32,17 @@
 
     void set(const GrMatrix& m) {
         Gr_bzero(fMat, sizeof(fMat));
-        fMat[0]  = GrScalarToFloat(m[GrMatrix::kScaleX]);
-        fMat[4]  = GrScalarToFloat(m[GrMatrix::kSkewX]);
-        fMat[12] = GrScalarToFloat(m[GrMatrix::kTransX]);
+        fMat[0]  = GrScalarToFloat(m[GrMatrix::kMScaleX]);
+        fMat[4]  = GrScalarToFloat(m[GrMatrix::kMSkewX]);
+        fMat[12] = GrScalarToFloat(m[GrMatrix::kMTransX]);
 
-        fMat[1]  = GrScalarToFloat(m[GrMatrix::kSkewY]);
-        fMat[5]  = GrScalarToFloat(m[GrMatrix::kScaleY]);
-        fMat[13] = GrScalarToFloat(m[GrMatrix::kTransY]);
+        fMat[1]  = GrScalarToFloat(m[GrMatrix::kMSkewY]);
+        fMat[5]  = GrScalarToFloat(m[GrMatrix::kMScaleY]);
+        fMat[13] = GrScalarToFloat(m[GrMatrix::kMTransY]);
 
-        fMat[3]  = GrScalarToFloat(m[GrMatrix::kPersp0]);
-        fMat[7]  = GrScalarToFloat(m[GrMatrix::kPersp1]);
-        fMat[15] = GrScalarToFloat(m[GrMatrix::kPersp2]);
+        fMat[3]  = GrScalarToFloat(m[GrMatrix::kMPersp0]);
+        fMat[7]  = GrScalarToFloat(m[GrMatrix::kMPersp1]);
+        fMat[15] = GrScalarToFloat(m[GrMatrix::kMPersp2]);
 
         fMat[10] = 1.f;    // z-scale
     }
diff --git a/gpu/src/GrGpuGLShaders.cpp b/gpu/src/GrGpuGLShaders.cpp
index c2b8971..3ce6e55 100644
--- a/gpu/src/GrGpuGLShaders.cpp
+++ b/gpu/src/GrGpuGLShaders.cpp
@@ -273,7 +273,8 @@
 
 void GrGpuGLShaders::flushViewMatrix() {
     GrAssert(NULL != fCurrDrawState.fRenderTarget);
-    GrMatrix m (
+    GrMatrix m;
+    m.setAll(
         GrIntToScalar(2) / fCurrDrawState.fRenderTarget->width(), 0, -GR_Scalar1,
         0,-GrIntToScalar(2) / fCurrDrawState.fRenderTarget->height(), GR_Scalar1,
         0, 0, GrMatrix::I()[8]);
@@ -282,15 +283,15 @@
     // ES doesn't allow you to pass true to the transpose param,
     // so do our own transpose
     GrScalar mt[]  = {
-        m[GrMatrix::kScaleX],
-        m[GrMatrix::kSkewY],
-        m[GrMatrix::kPersp0],
-        m[GrMatrix::kSkewX],
-        m[GrMatrix::kScaleY],
-        m[GrMatrix::kPersp1],
-        m[GrMatrix::kTransX],
-        m[GrMatrix::kTransY],
-        m[GrMatrix::kPersp2]
+        m[GrMatrix::kMScaleX],
+        m[GrMatrix::kMSkewY],
+        m[GrMatrix::kMPersp0],
+        m[GrMatrix::kMSkewX],
+        m[GrMatrix::kMScaleY],
+        m[GrMatrix::kMPersp1],
+        m[GrMatrix::kMTransX],
+        m[GrMatrix::kMTransY],
+        m[GrMatrix::kMPersp2]
     };
 
     if (GrGLProgram::kSetAsAttribute ==  
@@ -327,15 +328,15 @@
             // ES doesn't allow you to pass true to the transpose param,
             // so do our own transpose
             GrScalar mt[]  = {
-                m[GrMatrix::kScaleX],
-                m[GrMatrix::kSkewY],
-                m[GrMatrix::kPersp0],
-                m[GrMatrix::kSkewX],
-                m[GrMatrix::kScaleY],
-                m[GrMatrix::kPersp1],
-                m[GrMatrix::kTransX],
-                m[GrMatrix::kTransY],
-                m[GrMatrix::kPersp2]
+                m[GrMatrix::kMScaleX],
+                m[GrMatrix::kMSkewY],
+                m[GrMatrix::kMPersp0],
+                m[GrMatrix::kMSkewX],
+                m[GrMatrix::kMScaleY],
+                m[GrMatrix::kMPersp1],
+                m[GrMatrix::kMTransX],
+                m[GrMatrix::kMTransY],
+                m[GrMatrix::kMPersp2]
             };
             if (GrGLProgram::kSetAsAttribute ==
                 fProgramData->fUniLocations.fStages[s].fTextureMatrixUni) {
diff --git a/gpu/src/GrMatrix.cpp b/gpu/src/GrMatrix.cpp
index c88c6e1..476d9a2 100644
--- a/gpu/src/GrMatrix.cpp
+++ b/gpu/src/GrMatrix.cpp
@@ -19,6 +19,7 @@
 #include "GrRect.h"
 #include <stddef.h>
 
+#if 0
 #if GR_SCALAR_IS_FLOAT
     const GrScalar GrMatrix::gRESCALE(GR_Scalar1);
 #else
@@ -688,6 +689,7 @@
 }
 
 ///////////////////////////////////////////////////////////////////////////////
+#endif
 
 int Gr_clz(uint32_t n) {
     if (0 == n) {
@@ -716,4 +718,3 @@
     }
     return count;
 }
-
diff --git a/gpu/src/gr_unittests.cpp b/gpu/src/gr_unittests.cpp
index fd27f19..320dd15 100644
--- a/gpu/src/gr_unittests.cpp
+++ b/gpu/src/gr_unittests.cpp
@@ -152,7 +152,6 @@
     test_tdarray();
     test_bsearch();
     test_binHashKey();
-    GrMatrix::UnitTest();
     GrRedBlackTree<int>::UnitTest();
     GrPath::ConvexUnitTest();
     GrDrawTarget::VertexLayoutUnitTest();
diff --git a/include/core/SkMatrix.h b/include/core/SkMatrix.h
index 5ba9223..7c77902 100644
--- a/include/core/SkMatrix.h
+++ b/include/core/SkMatrix.h
@@ -70,6 +70,15 @@
         }
         return (fTypeMask & kRectStaysRect_Mask) != 0;
     }
+    // alias for rectStaysRect()
+    bool preservesAxisAlignment() const { return this->rectStaysRect(); }
+
+    /**
+     *  Returns true if the perspective contains perspective elements.
+     */
+    bool hasPerspective() const {
+        return SkToBool(this->getType() & kPerspective_Mask);
+    }
 
     enum {
         kMScaleX,
@@ -123,10 +132,27 @@
     void setPerspX(SkScalar v) { this->set(kMPersp0, v); }
     void setPerspY(SkScalar v) { this->set(kMPersp1, v); }
 
+    void setAll(SkScalar scaleX, SkScalar skewX, SkScalar transX,
+                SkScalar skewY, SkScalar scaleY, SkScalar transY,
+                SkScalar persp0, SkScalar persp1, SkScalar persp2) {
+        fMat[kMScaleX] = scaleX;
+        fMat[kMSkewX]  = skewX;
+        fMat[kMTransX] = transX;
+        fMat[kMSkewY]  = skewY;
+        fMat[kMScaleY] = scaleY;
+        fMat[kMTransY] = transY;
+        fMat[kMPersp0] = persp0;
+        fMat[kMPersp1] = persp1;
+        fMat[kMPersp2] = persp2;
+        this->setTypeMask(kUnknown_Mask);
+    }
+        
     /** Set the matrix to identity
     */
     void reset();
-    
+    // alias for reset()
+    void setIdentity() { this->reset(); }
+
     /** Set the matrix to translate by (dx, dy).
     */
     void setTranslate(SkScalar dx, SkScalar dy);
@@ -369,6 +395,13 @@
         return this->mapRect(rect, *rect);
     }
 
+    void mapPointsWithStride(SkPoint pts[], size_t stride, int count) const {
+        for (int i = 0; i < count; ++i) {            
+            this->mapPoints(pts, pts, 1);
+            pts = (SkPoint*)((intptr_t)pts + stride);
+        }
+    }
+    
     /** Return the mean radius of a circle after it has been mapped by
         this matrix. NOTE: in perspective this value assumes the circle
         has its center at the origin.
@@ -425,6 +458,25 @@
     void dump() const;
     void toDumpString(SkString*) const;
 
+    /**
+     * Calculates the maximum stretching factor of the matrix. Only defined if
+     * the matrix does not have perspective.
+     *
+     * @return maximum strecthing factor or negative if matrix has perspective.
+     */
+    SkScalar getMaxStretch() const;
+
+    /**
+     *  Return a reference to a const identity matrix
+     */
+    static const SkMatrix& I();
+
+    /**
+     *  Return a reference to a const matrix that is "invalid", one that could
+     *  never be used.
+     */
+    static const SkMatrix& InvalidMatrix();
+
 private:
     enum {
         /** Set if the matrix will map a rectangle to another rectangle. This
diff --git a/include/gpu/SkGr.h b/include/gpu/SkGr.h
index eef70b1..75099b2 100644
--- a/include/gpu/SkGr.h
+++ b/include/gpu/SkGr.h
@@ -117,18 +117,6 @@
         return BitmapConfig2PixelConfig(bm.config(), bm.isOpaque());
     }
 
-    static void SkMatrix2GrMatrix(const SkMatrix& m, GrMatrix* g) {
-        g->setAll(SkScalarToGrScalar(m[0]),
-                  SkScalarToGrScalar(m[1]),
-                  SkScalarToGrScalar(m[2]),
-                  SkScalarToGrScalar(m[3]),
-                  SkScalarToGrScalar(m[4]),
-                  SkScalarToGrScalar(m[5]),
-                  SkScalarToGrScalar(m[6]),
-                  SkScalarToGrScalar(m[7]),
-                  SkScalarToGrScalar(m[8]));
-    }
-
     static GrColor SkColor2GrColor(SkColor c) {
         SkPMColor pm = SkPreMultiplyColor(c);
         unsigned r = SkGetPackedR32(pm);
diff --git a/src/core/SkMatrix.cpp b/src/core/SkMatrix.cpp
index f2d1708..983c8d2 100644
--- a/src/core/SkMatrix.cpp
+++ b/src/core/SkMatrix.cpp
@@ -1586,6 +1586,95 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
+SkScalar SkMatrix::getMaxStretch() const {
+    TypeMask mask = this->getType();
+
+    if (mask & kPerspective_Mask) {
+        return -SK_Scalar1;
+    }
+    
+    SkScalar stretch;
+    
+    if (this->isIdentity()) {
+        stretch = SK_Scalar1;
+    } else if (!(mask & kAffine_Mask)) {
+        stretch = SkMaxScalar(SkScalarAbs(fMat[kMScaleX]), SkScalarAbs(fMat[kMScaleY]));
+#if 0   // don't have this bit
+    } else if (mask & kZeroScale_TypeBit) {
+        stretch = SkMaxScalar(SkScalarAbs(fM[kSkewX]), SkScalarAbs(fM[kSkewY]));
+#endif
+    } else {
+        // ignore the translation part of the matrix, just look at 2x2 portion.
+        // compute singular values, take largest abs value.
+        // [a b; b c] = A^T*A
+        SkScalar a = SkScalarMul(fMat[kMScaleX], fMat[kMScaleX]) + SkScalarMul(fMat[kMSkewY],  fMat[kMSkewY]);
+        SkScalar b = SkScalarMul(fMat[kMScaleX], fMat[kMSkewX]) +  SkScalarMul(fMat[kMScaleY], fMat[kMSkewY]);
+        SkScalar c = SkScalarMul(fMat[kMSkewX],  fMat[kMSkewX]) +  SkScalarMul(fMat[kMScaleY], fMat[kMScaleY]);
+        // eigenvalues of A^T*A are the squared singular values of A.
+        // characteristic equation is det((A^T*A) - l*I) = 0
+        // l^2 - (a + c)l + (ac-b^2)
+        // solve using quadratic equation (divisor is non-zero since l^2 has 1 coeff
+        // and roots are guaraunteed to be pos and real).
+        SkScalar largerRoot;
+        SkScalar bSqd = SkScalarMul(b,b);
+        if (bSqd <= SkFloatToScalar(1e-10)) { // will be true if upper left 2x2 is orthogonal, which is common, so save some math
+            largerRoot = SkMaxScalar(a, c);
+        } else {
+            SkScalar aminusc = a - c;
+            SkScalar apluscdiv2 = (a + c) / 2;
+            SkScalar x = SkScalarSqrt(SkScalarMul(aminusc, aminusc) + 4 * bSqd) / 2;
+            largerRoot = apluscdiv2 + x;
+        }
+        
+        stretch = SkScalarSqrt(largerRoot);
+    }
+#if defined(SK_DEBUG) && 0
+    // test a bunch of vectors. None should be scaled by more than stretch
+    // (modulo some error) and we should find a vector that is scaled by almost
+    // stretch.
+    SkPoint pt;
+    SkScalar max = 0;
+    for (int i = 0; i < 1000; ++i) {
+        SkScalar x = (float)rand() / RAND_MAX;
+        SkScalar y = sqrtf(1 - (x*x));
+        pt.fX = fMat[kMScaleX]*x + fMat[kMSkewX]*y;
+        pt.fY = fMat[kMSkewY]*x + fMat[kMScaleY]*y;
+        SkScalar d = pt.distanceToOrigin();
+        SkASSERT(d <= (1.0001 * stretch));
+        if (max < pt.distanceToOrigin()) {
+            max = pt.distanceToOrigin();
+        }
+    }
+    SkASSERT((stretch - max) < .05*stretch);
+#endif
+    return stretch;
+}
+
+const SkMatrix& SkMatrix::I() {
+    static SkMatrix gIdentity;
+    static bool gOnce;
+    if (!gOnce) {
+        gIdentity.reset();
+        gOnce = true;
+    }
+    return gIdentity;
+};
+
+const SkMatrix& SkMatrix::InvalidMatrix() {
+    static SkMatrix gInvalid;
+    static bool gOnce;
+    if (!gOnce) {
+        gInvalid.setAll(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
+                        SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
+                        SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
+        gInvalid.getType(); // force the type to be computed
+        gOnce = true;
+    }
+    return gInvalid;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
 uint32_t SkMatrix::flatten(void* buffer) const {
     // TODO write less for simple matrices
     if (buffer) {
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index afd5bd3..8818dc0 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -39,23 +39,6 @@
     #define CHECK_SHOULD_DRAW(draw) this->prepareRenderTarget(draw)
 #endif
 
-class SkAutoExtMatrix {
-public:
-    SkAutoExtMatrix(const SkMatrix* extMatrix) {
-        if (extMatrix) {
-            SkGr::SkMatrix2GrMatrix(*extMatrix, &fMatrix);
-            fExtMatrix = &fMatrix;
-        } else {
-            fExtMatrix = NULL;
-        }
-    }
-    const GrMatrix* extMatrix() const { return fExtMatrix; }
-
-private:
-    GrMatrix    fMatrix;
-    GrMatrix*   fExtMatrix; // NULL or &fMatrix
-};
-
 ///////////////////////////////////////////////////////////////////////////////
 
 SkGpuDevice::SkAutoCachedTexture::
@@ -279,9 +262,7 @@
                                const SkClipStack& clipStack,
                                const SkRegion& clipRegion,
                                const SkIPoint& origin) {
-    GrMatrix grmat;
-    SkGr::SkMatrix2GrMatrix(matrix, &grmat);
-    context->setMatrix(grmat);
+    context->setMatrix(matrix);
 
     SkGrClipIterator iter;
     iter.reset(clipStack);
@@ -460,9 +441,7 @@
         GrScalar s = GrFixedToScalar(GR_Fixed1 / bitmap.width());
         matrix.postScale(s, s);
     }
-    GrMatrix grMat;
-    SkGr::SkMatrix2GrMatrix(matrix, &grMat);
-    grPaint->fSampler.setMatrix(grMat);
+    grPaint->fSampler.setMatrix(matrix);
 
     return true;
 }
@@ -975,10 +954,7 @@
                       GrFixedToScalar((srcRect.fRight << 16)  / bitmap.width()),
                       GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
 
-    GrMatrix grMat;
-    SkGr::SkMatrix2GrMatrix(m, &grMat);
-
-    fContext->drawRectToRect(*grPaint, dstRect, paintRect, &grMat);
+    fContext->drawRectToRect(*grPaint, dstRect, paintRect, &m);
 }
 
 void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
@@ -1178,7 +1154,6 @@
         // this guy will just call our drawPath()
         draw.drawText((const char*)text, byteLength, x, y, paint);
     } else {
-        SkAutoExtMatrix aem(draw.fExtMatrix);
         SkDraw myDraw(draw);
 
         GrPaint grPaint;
@@ -1187,7 +1162,7 @@
         if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
             return;
         }
-        GrTextContext context(fContext, grPaint, aem.extMatrix());
+        GrTextContext context(fContext, grPaint, draw.fExtMatrix);
         myDraw.fProcs = this->initDrawForText(&context);
         this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
     }
@@ -1204,7 +1179,6 @@
         draw.drawPosText((const char*)text, byteLength, pos, constY,
                          scalarsPerPos, paint);
     } else {
-        SkAutoExtMatrix aem(draw.fExtMatrix);
         SkDraw myDraw(draw);
 
         GrPaint grPaint;
@@ -1213,7 +1187,7 @@
             return;
         }
 
-        GrTextContext context(fContext, grPaint, aem.extMatrix());
+        GrTextContext context(fContext, grPaint, draw.fExtMatrix);
         myDraw.fProcs = this->initDrawForText(&context);
         this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
                                      scalarsPerPos, paint);