[gpu] Remove getMaxStretch for perspective, use mapRadius for perspective path subdiv tol, add test

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



git-svn-id: http://skia.googlecode.com/svn/trunk@2246 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/tests/MatrixTest.cpp b/tests/MatrixTest.cpp
index df24a5a..4638fe1 100644
--- a/tests/MatrixTest.cpp
+++ b/tests/MatrixTest.cpp
@@ -7,6 +7,7 @@
  */
 #include "Test.h"
 #include "SkMatrix.h"
+#include "SkRandom.h"
 
 static bool nearly_equal_scalar(SkScalar a, SkScalar b) {
     // Note that we get more compounded error for multiple operations when
@@ -55,6 +56,94 @@
     REPORTER_ASSERT(reporter, memcmp(buffer, buffer2, size1) == 0);
 }
 
+void test_matrix_max_stretch(skiatest::Reporter* reporter) {
+    SkMatrix identity;
+    identity.reset();
+    REPORTER_ASSERT(reporter, SK_Scalar1 == identity.getMaxStretch());
+
+    SkMatrix scale;
+    scale.setScale(SK_Scalar1 * 2, SK_Scalar1 * 4);
+    REPORTER_ASSERT(reporter, SK_Scalar1 * 4 == scale.getMaxStretch());
+
+    SkMatrix rot90Scale;
+    rot90Scale.setRotate(90 * SK_Scalar1);
+    rot90Scale.postScale(SK_Scalar1 / 4, SK_Scalar1 / 2);
+    REPORTER_ASSERT(reporter, SK_Scalar1 / 2 == rot90Scale.getMaxStretch());
+
+    SkMatrix rotate;
+    rotate.setRotate(128 * SK_Scalar1);
+    REPORTER_ASSERT(reporter, SkScalarAbs(SK_Scalar1 - rotate.getMaxStretch()) <= SK_ScalarNearlyZero);
+
+    SkMatrix translate;
+    translate.setTranslate(10 * SK_Scalar1, -5 * SK_Scalar1);
+    REPORTER_ASSERT(reporter, SK_Scalar1 == translate.getMaxStretch());
+
+    SkMatrix perspX;
+    perspX.reset();
+    perspX.setPerspX(SK_Scalar1 / 1000);
+    REPORTER_ASSERT(reporter, -SK_Scalar1 == perspX.getMaxStretch());
+
+    SkMatrix perspY;
+    perspY.reset();
+    perspY.setPerspX(-SK_Scalar1 / 500);
+    REPORTER_ASSERT(reporter, -SK_Scalar1 == perspY.getMaxStretch());
+
+    SkMatrix baseMats[] = {scale, rot90Scale, rotate,
+                           translate, perspX, perspY};
+    SkMatrix mats[2*SK_ARRAY_COUNT(baseMats)];
+    for (int i = 0; i < SK_ARRAY_COUNT(baseMats); ++i) {
+        mats[i] = baseMats[i];
+        bool invertable = mats[i].invert(&mats[i + SK_ARRAY_COUNT(baseMats)]);
+        REPORTER_ASSERT(reporter, invertable);
+    }
+    SkRandom rand;
+    for (int m = 0; m < 1000; ++m) {
+        SkMatrix mat;
+        mat.reset();
+        for (int i = 0; i < 4; ++i) {
+            int x = rand.nextU() % SK_ARRAY_COUNT(mats);
+            mat.postConcat(mats[x]);
+        }
+        SkScalar stretch = mat.getMaxStretch();
+        
+        if ((stretch < 0) != mat.hasPerspective()) {
+            stretch = mat.getMaxStretch();
+        }
+
+        REPORTER_ASSERT(reporter, (stretch < 0) == mat.hasPerspective());
+
+        if (mat.hasPerspective()) {
+            m -= 1; // try another non-persp matrix
+            continue;
+        }
+
+        // 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.
+        static const SkScalar gStretchTol = (105 * SK_Scalar1) / 100;
+        static const SkScalar gMaxStretchTol = (97 * SK_Scalar1) / 100;
+        SkScalar max = 0;
+        SkVector vectors[1000];
+        for (int i = 0; i < SK_ARRAY_COUNT(vectors); ++i) {
+            vectors[i].fX = rand.nextSScalar1();
+            vectors[i].fY = rand.nextSScalar1();
+            if (!vectors[i].normalize()) {
+                i -= 1;
+                continue;
+            }
+        }
+        mat.mapVectors(vectors, SK_ARRAY_COUNT(vectors));
+        for (int i = 0; i < SK_ARRAY_COUNT(vectors); ++i) {
+            SkScalar d = vectors[i].length();
+            REPORTER_ASSERT(reporter, SkScalarDiv(d, stretch) < gStretchTol);
+            if (max < d) {
+                max = d;
+            }
+        }
+        REPORTER_ASSERT(reporter, SkScalarDiv(max, stretch) >= gMaxStretchTol);
+    }
+}
+
 void TestMatrix(skiatest::Reporter* reporter) {
     SkMatrix    mat, inverse, iden1, iden2;
 
@@ -146,6 +235,8 @@
 
     mat.set(SkMatrix::kMPersp1, SkIntToScalar(1));
     REPORTER_ASSERT(reporter, !mat.asAffine(affine));
+
+    test_matrix_max_stretch(reporter);
 }
 
 #include "TestClassDef.h"