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/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);