Home | History | Annotate | Download | only in tests
      1 
      2 /*
      3  * Copyright 2011 Google Inc.
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 #include "Test.h"
      9 #include "SkMath.h"
     10 #include "SkMatrix.h"
     11 #include "SkRandom.h"
     12 
     13 static bool nearly_equal_scalar(SkScalar a, SkScalar b) {
     14     // Note that we get more compounded error for multiple operations when
     15     // SK_SCALAR_IS_FIXED.
     16 #ifdef SK_SCALAR_IS_FLOAT
     17     const SkScalar tolerance = SK_Scalar1 / 200000;
     18 #else
     19     const SkScalar tolerance = SK_Scalar1 / 1024;
     20 #endif
     21 
     22     return SkScalarAbs(a - b) <= tolerance;
     23 }
     24 
     25 static bool nearly_equal(const SkMatrix& a, const SkMatrix& b) {
     26     for (int i = 0; i < 9; i++) {
     27         if (!nearly_equal_scalar(a[i], b[i])) {
     28             printf("not equal %g %g\n", (float)a[i], (float)b[i]);
     29             return false;
     30         }
     31     }
     32     return true;
     33 }
     34 
     35 static bool is_identity(const SkMatrix& m) {
     36     SkMatrix identity;
     37     identity.reset();
     38     return nearly_equal(m, identity);
     39 }
     40 
     41 static void test_flatten(skiatest::Reporter* reporter, const SkMatrix& m) {
     42     // add 100 in case we have a bug, I don't want to kill my stack in the test
     43     char buffer[SkMatrix::kMaxFlattenSize + 100];
     44     uint32_t size1 = m.flatten(NULL);
     45     uint32_t size2 = m.flatten(buffer);
     46     REPORTER_ASSERT(reporter, size1 == size2);
     47     REPORTER_ASSERT(reporter, size1 <= SkMatrix::kMaxFlattenSize);
     48 
     49     SkMatrix m2;
     50     uint32_t size3 = m2.unflatten(buffer);
     51     REPORTER_ASSERT(reporter, size1 == size2);
     52     REPORTER_ASSERT(reporter, m == m2);
     53 
     54     char buffer2[SkMatrix::kMaxFlattenSize + 100];
     55     size3 = m2.flatten(buffer2);
     56     REPORTER_ASSERT(reporter, size1 == size2);
     57     REPORTER_ASSERT(reporter, memcmp(buffer, buffer2, size1) == 0);
     58 }
     59 
     60 void test_matrix_max_stretch(skiatest::Reporter* reporter) {
     61     SkMatrix identity;
     62     identity.reset();
     63     REPORTER_ASSERT(reporter, SK_Scalar1 == identity.getMaxStretch());
     64 
     65     SkMatrix scale;
     66     scale.setScale(SK_Scalar1 * 2, SK_Scalar1 * 4);
     67     REPORTER_ASSERT(reporter, SK_Scalar1 * 4 == scale.getMaxStretch());
     68 
     69     SkMatrix rot90Scale;
     70     rot90Scale.setRotate(90 * SK_Scalar1);
     71     rot90Scale.postScale(SK_Scalar1 / 4, SK_Scalar1 / 2);
     72     REPORTER_ASSERT(reporter, SK_Scalar1 / 2 == rot90Scale.getMaxStretch());
     73 
     74     SkMatrix rotate;
     75     rotate.setRotate(128 * SK_Scalar1);
     76     REPORTER_ASSERT(reporter, SkScalarAbs(SK_Scalar1 - rotate.getMaxStretch()) <= SK_ScalarNearlyZero);
     77 
     78     SkMatrix translate;
     79     translate.setTranslate(10 * SK_Scalar1, -5 * SK_Scalar1);
     80     REPORTER_ASSERT(reporter, SK_Scalar1 == translate.getMaxStretch());
     81 
     82     SkMatrix perspX;
     83     perspX.reset();
     84     perspX.setPerspX(SkScalarToPersp(SK_Scalar1 / 1000));
     85     REPORTER_ASSERT(reporter, -SK_Scalar1 == perspX.getMaxStretch());
     86 
     87     SkMatrix perspY;
     88     perspY.reset();
     89     perspY.setPerspX(SkScalarToPersp(-SK_Scalar1 / 500));
     90     REPORTER_ASSERT(reporter, -SK_Scalar1 == perspY.getMaxStretch());
     91 
     92     SkMatrix baseMats[] = {scale, rot90Scale, rotate,
     93                            translate, perspX, perspY};
     94     SkMatrix mats[2*SK_ARRAY_COUNT(baseMats)];
     95     for (size_t i = 0; i < SK_ARRAY_COUNT(baseMats); ++i) {
     96         mats[i] = baseMats[i];
     97         bool invertable = mats[i].invert(&mats[i + SK_ARRAY_COUNT(baseMats)]);
     98         REPORTER_ASSERT(reporter, invertable);
     99     }
    100     SkRandom rand;
    101     for (int m = 0; m < 1000; ++m) {
    102         SkMatrix mat;
    103         mat.reset();
    104         for (int i = 0; i < 4; ++i) {
    105             int x = rand.nextU() % SK_ARRAY_COUNT(mats);
    106             mat.postConcat(mats[x]);
    107         }
    108         SkScalar stretch = mat.getMaxStretch();
    109 
    110         if ((stretch < 0) != mat.hasPerspective()) {
    111             stretch = mat.getMaxStretch();
    112         }
    113 
    114         REPORTER_ASSERT(reporter, (stretch < 0) == mat.hasPerspective());
    115 
    116         if (mat.hasPerspective()) {
    117             m -= 1; // try another non-persp matrix
    118             continue;
    119         }
    120 
    121         // test a bunch of vectors. None should be scaled by more than stretch
    122         // (modulo some error) and we should find a vector that is scaled by
    123         // almost stretch.
    124         static const SkScalar gStretchTol = (105 * SK_Scalar1) / 100;
    125         static const SkScalar gMaxStretchTol = (97 * SK_Scalar1) / 100;
    126         SkScalar max = 0;
    127         SkVector vectors[1000];
    128         for (size_t i = 0; i < SK_ARRAY_COUNT(vectors); ++i) {
    129             vectors[i].fX = rand.nextSScalar1();
    130             vectors[i].fY = rand.nextSScalar1();
    131             if (!vectors[i].normalize()) {
    132                 i -= 1;
    133                 continue;
    134             }
    135         }
    136         mat.mapVectors(vectors, SK_ARRAY_COUNT(vectors));
    137         for (size_t i = 0; i < SK_ARRAY_COUNT(vectors); ++i) {
    138             SkScalar d = vectors[i].length();
    139             REPORTER_ASSERT(reporter, SkScalarDiv(d, stretch) < gStretchTol);
    140             if (max < d) {
    141                 max = d;
    142             }
    143         }
    144         REPORTER_ASSERT(reporter, SkScalarDiv(max, stretch) >= gMaxStretchTol);
    145     }
    146 }
    147 
    148 void TestMatrix(skiatest::Reporter* reporter) {
    149     SkMatrix    mat, inverse, iden1, iden2;
    150 
    151     mat.reset();
    152     mat.setTranslate(SK_Scalar1, SK_Scalar1);
    153     mat.invert(&inverse);
    154     iden1.setConcat(mat, inverse);
    155     REPORTER_ASSERT(reporter, is_identity(iden1));
    156 
    157     mat.setScale(SkIntToScalar(2), SkIntToScalar(2));
    158     mat.invert(&inverse);
    159     iden1.setConcat(mat, inverse);
    160     REPORTER_ASSERT(reporter, is_identity(iden1));
    161     test_flatten(reporter, mat);
    162 
    163     mat.setScale(SK_Scalar1/2, SK_Scalar1/2);
    164     mat.invert(&inverse);
    165     iden1.setConcat(mat, inverse);
    166     REPORTER_ASSERT(reporter, is_identity(iden1));
    167     test_flatten(reporter, mat);
    168 
    169     mat.setScale(SkIntToScalar(3), SkIntToScalar(5), SkIntToScalar(20), 0);
    170     mat.postRotate(SkIntToScalar(25));
    171     REPORTER_ASSERT(reporter, mat.invert(NULL));
    172     mat.invert(&inverse);
    173     iden1.setConcat(mat, inverse);
    174     REPORTER_ASSERT(reporter, is_identity(iden1));
    175     iden2.setConcat(inverse, mat);
    176     REPORTER_ASSERT(reporter, is_identity(iden2));
    177     test_flatten(reporter, mat);
    178     test_flatten(reporter, iden2);
    179 
    180     // rectStaysRect test
    181     {
    182         static const struct {
    183             SkScalar    m00, m01, m10, m11;
    184             bool        mStaysRect;
    185         }
    186         gRectStaysRectSamples[] = {
    187             {          0,          0,          0,           0, false },
    188             {          0,          0,          0,  SK_Scalar1, false },
    189             {          0,          0, SK_Scalar1,           0, false },
    190             {          0,          0, SK_Scalar1,  SK_Scalar1, false },
    191             {          0, SK_Scalar1,          0,           0, false },
    192             {          0, SK_Scalar1,          0,  SK_Scalar1, false },
    193             {          0, SK_Scalar1, SK_Scalar1,           0, true },
    194             {          0, SK_Scalar1, SK_Scalar1,  SK_Scalar1, false },
    195             { SK_Scalar1,          0,          0,           0, false },
    196             { SK_Scalar1,          0,          0,  SK_Scalar1, true },
    197             { SK_Scalar1,          0, SK_Scalar1,           0, false },
    198             { SK_Scalar1,          0, SK_Scalar1,  SK_Scalar1, false },
    199             { SK_Scalar1, SK_Scalar1,          0,           0, false },
    200             { SK_Scalar1, SK_Scalar1,          0,  SK_Scalar1, false },
    201             { SK_Scalar1, SK_Scalar1, SK_Scalar1,           0, false },
    202             { SK_Scalar1, SK_Scalar1, SK_Scalar1,  SK_Scalar1, false }
    203         };
    204 
    205         for (size_t i = 0; i < SK_ARRAY_COUNT(gRectStaysRectSamples); i++) {
    206             SkMatrix    m;
    207 
    208             m.reset();
    209             m.set(SkMatrix::kMScaleX, gRectStaysRectSamples[i].m00);
    210             m.set(SkMatrix::kMSkewX,  gRectStaysRectSamples[i].m01);
    211             m.set(SkMatrix::kMSkewY,  gRectStaysRectSamples[i].m10);
    212             m.set(SkMatrix::kMScaleY, gRectStaysRectSamples[i].m11);
    213             REPORTER_ASSERT(reporter,
    214                     m.rectStaysRect() == gRectStaysRectSamples[i].mStaysRect);
    215         }
    216     }
    217 
    218     mat.reset();
    219     mat.set(SkMatrix::kMScaleX, SkIntToScalar(1));
    220     mat.set(SkMatrix::kMSkewX,  SkIntToScalar(2));
    221     mat.set(SkMatrix::kMTransX, SkIntToScalar(3));
    222     mat.set(SkMatrix::kMSkewY,  SkIntToScalar(4));
    223     mat.set(SkMatrix::kMScaleY, SkIntToScalar(5));
    224     mat.set(SkMatrix::kMTransY, SkIntToScalar(6));
    225     SkScalar affine[6];
    226     REPORTER_ASSERT(reporter, mat.asAffine(affine));
    227 
    228     #define affineEqual(e) affine[SkMatrix::kA##e] == mat.get(SkMatrix::kM##e)
    229     REPORTER_ASSERT(reporter, affineEqual(ScaleX));
    230     REPORTER_ASSERT(reporter, affineEqual(SkewY));
    231     REPORTER_ASSERT(reporter, affineEqual(SkewX));
    232     REPORTER_ASSERT(reporter, affineEqual(ScaleY));
    233     REPORTER_ASSERT(reporter, affineEqual(TransX));
    234     REPORTER_ASSERT(reporter, affineEqual(TransY));
    235     #undef affineEqual
    236 
    237     mat.set(SkMatrix::kMPersp1, SkScalarToPersp(SK_Scalar1 / 2));
    238     REPORTER_ASSERT(reporter, !mat.asAffine(affine));
    239 
    240     test_matrix_max_stretch(reporter);
    241 }
    242 
    243 #include "TestClassDef.h"
    244 DEFINE_TESTCLASS("Matrix", MatrixTestClass, TestMatrix)
    245