1#include "Test.h"
2#include "SkMatrix.h"
3
4static bool nearly_equal_scalar(SkScalar a, SkScalar b) {
5    // Note that we get more compounded error for multiple operations when
6    // SK_SCALAR_IS_FIXED.
7#ifdef SK_SCALAR_IS_FLOAT
8    const SkScalar tolerance = SK_Scalar1 / 200000;
9#else
10    const SkScalar tolerance = SK_Scalar1 / 1024;
11#endif
12
13    return SkScalarAbs(a - b) <= tolerance;
14}
15
16static bool nearly_equal(const SkMatrix& a, const SkMatrix& b) {
17    for (int i = 0; i < 9; i++) {
18        if (!nearly_equal_scalar(a[i], b[i])) {
19            printf("not equal %g %g\n", (float)a[i], (float)b[i]);
20            return false;
21        }
22    }
23    return true;
24}
25
26static bool is_identity(const SkMatrix& m) {
27    SkMatrix identity;
28    identity.reset();
29    return nearly_equal(m, identity);
30}
31
32static void test_flatten(skiatest::Reporter* reporter, const SkMatrix& m) {
33    // add 100 in case we have a bug, I don't want to kill my stack in the test
34    char buffer[SkMatrix::kMaxFlattenSize + 100];
35    uint32_t size1 = m.flatten(NULL);
36    uint32_t size2 = m.flatten(buffer);
37    REPORTER_ASSERT(reporter, size1 == size2);
38    REPORTER_ASSERT(reporter, size1 <= SkMatrix::kMaxFlattenSize);
39
40    SkMatrix m2;
41    uint32_t size3 = m2.unflatten(buffer);
42    REPORTER_ASSERT(reporter, size1 == size2);
43    REPORTER_ASSERT(reporter, m == m2);
44
45    char buffer2[SkMatrix::kMaxFlattenSize + 100];
46    size3 = m2.flatten(buffer2);
47    REPORTER_ASSERT(reporter, size1 == size2);
48    REPORTER_ASSERT(reporter, memcmp(buffer, buffer2, size1) == 0);
49}
50
51void TestMatrix(skiatest::Reporter* reporter) {
52    SkMatrix    mat, inverse, iden1, iden2;
53
54    mat.reset();
55    mat.setTranslate(SK_Scalar1, SK_Scalar1);
56    mat.invert(&inverse);
57    iden1.setConcat(mat, inverse);
58    REPORTER_ASSERT(reporter, is_identity(iden1));
59
60    mat.setScale(SkIntToScalar(2), SkIntToScalar(2));
61    mat.invert(&inverse);
62    iden1.setConcat(mat, inverse);
63    REPORTER_ASSERT(reporter, is_identity(iden1));
64    test_flatten(reporter, mat);
65
66    mat.setScale(SK_Scalar1/2, SK_Scalar1/2);
67    mat.invert(&inverse);
68    iden1.setConcat(mat, inverse);
69    REPORTER_ASSERT(reporter, is_identity(iden1));
70    test_flatten(reporter, mat);
71
72    mat.setScale(SkIntToScalar(3), SkIntToScalar(5), SkIntToScalar(20), 0);
73    mat.postRotate(SkIntToScalar(25));
74    REPORTER_ASSERT(reporter, mat.invert(NULL));
75    mat.invert(&inverse);
76    iden1.setConcat(mat, inverse);
77    REPORTER_ASSERT(reporter, is_identity(iden1));
78    iden2.setConcat(inverse, mat);
79    REPORTER_ASSERT(reporter, is_identity(iden2));
80    test_flatten(reporter, mat);
81    test_flatten(reporter, iden2);
82
83    // rectStaysRect test
84    {
85        static const struct {
86            SkScalar    m00, m01, m10, m11;
87            bool        mStaysRect;
88        }
89        gRectStaysRectSamples[] = {
90            {          0,          0,          0,           0, false },
91            {          0,          0,          0,  SK_Scalar1, false },
92            {          0,          0, SK_Scalar1,           0, false },
93            {          0,          0, SK_Scalar1,  SK_Scalar1, false },
94            {          0, SK_Scalar1,          0,           0, false },
95            {          0, SK_Scalar1,          0,  SK_Scalar1, false },
96            {          0, SK_Scalar1, SK_Scalar1,           0, true },
97            {          0, SK_Scalar1, SK_Scalar1,  SK_Scalar1, false },
98            { SK_Scalar1,          0,          0,           0, false },
99            { SK_Scalar1,          0,          0,  SK_Scalar1, true },
100            { SK_Scalar1,          0, SK_Scalar1,           0, false },
101            { SK_Scalar1,          0, SK_Scalar1,  SK_Scalar1, false },
102            { SK_Scalar1, SK_Scalar1,          0,           0, false },
103            { SK_Scalar1, SK_Scalar1,          0,  SK_Scalar1, false },
104            { SK_Scalar1, SK_Scalar1, SK_Scalar1,           0, false },
105            { SK_Scalar1, SK_Scalar1, SK_Scalar1,  SK_Scalar1, false }
106        };
107
108        for (size_t i = 0; i < SK_ARRAY_COUNT(gRectStaysRectSamples); i++) {
109            SkMatrix    m;
110
111            m.reset();
112            m.set(SkMatrix::kMScaleX, gRectStaysRectSamples[i].m00);
113            m.set(SkMatrix::kMSkewX,  gRectStaysRectSamples[i].m01);
114            m.set(SkMatrix::kMSkewY,  gRectStaysRectSamples[i].m10);
115            m.set(SkMatrix::kMScaleY, gRectStaysRectSamples[i].m11);
116            REPORTER_ASSERT(reporter,
117                    m.rectStaysRect() == gRectStaysRectSamples[i].mStaysRect);
118        }
119    }
120}
121
122#include "TestClassDef.h"
123DEFINE_TESTCLASS("Matrix", MatrixTestClass, TestMatrix)
124