1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// MSVC++ requires this to be set before any other includes to get M_PI.
6#define _USE_MATH_DEFINES
7
8#include "ui/gfx/transform.h"
9
10#include <cmath>
11#include <ostream>
12#include <limits>
13
14#include "base/basictypes.h"
15#include "base/logging.h"
16#include "testing/gtest/include/gtest/gtest.h"
17#include "ui/gfx/box_f.h"
18#include "ui/gfx/point.h"
19#include "ui/gfx/point3_f.h"
20#include "ui/gfx/quad_f.h"
21#include "ui/gfx/transform_util.h"
22#include "ui/gfx/vector3d_f.h"
23
24namespace gfx {
25
26namespace {
27
28#define EXPECT_ROW1_EQ(a, b, c, d, transform)               \
29    EXPECT_FLOAT_EQ((a), (transform).matrix().get(0, 0));   \
30    EXPECT_FLOAT_EQ((b), (transform).matrix().get(0, 1));   \
31    EXPECT_FLOAT_EQ((c), (transform).matrix().get(0, 2));   \
32    EXPECT_FLOAT_EQ((d), (transform).matrix().get(0, 3));
33
34#define EXPECT_ROW2_EQ(a, b, c, d, transform)               \
35    EXPECT_FLOAT_EQ((a), (transform).matrix().get(1, 0));   \
36    EXPECT_FLOAT_EQ((b), (transform).matrix().get(1, 1));   \
37    EXPECT_FLOAT_EQ((c), (transform).matrix().get(1, 2));   \
38    EXPECT_FLOAT_EQ((d), (transform).matrix().get(1, 3));
39
40#define EXPECT_ROW3_EQ(a, b, c, d, transform)               \
41    EXPECT_FLOAT_EQ((a), (transform).matrix().get(2, 0));   \
42    EXPECT_FLOAT_EQ((b), (transform).matrix().get(2, 1));   \
43    EXPECT_FLOAT_EQ((c), (transform).matrix().get(2, 2));   \
44    EXPECT_FLOAT_EQ((d), (transform).matrix().get(2, 3));
45
46#define EXPECT_ROW4_EQ(a, b, c, d, transform)               \
47    EXPECT_FLOAT_EQ((a), (transform).matrix().get(3, 0));   \
48    EXPECT_FLOAT_EQ((b), (transform).matrix().get(3, 1));   \
49    EXPECT_FLOAT_EQ((c), (transform).matrix().get(3, 2));   \
50    EXPECT_FLOAT_EQ((d), (transform).matrix().get(3, 3));   \
51
52// Checking float values for equality close to zero is not robust using
53// EXPECT_FLOAT_EQ (see gtest documentation). So, to verify rotation matrices,
54// we must use a looser absolute error threshold in some places.
55#define EXPECT_ROW1_NEAR(a, b, c, d, transform, errorThreshold)         \
56    EXPECT_NEAR((a), (transform).matrix().get(0, 0), (errorThreshold)); \
57    EXPECT_NEAR((b), (transform).matrix().get(0, 1), (errorThreshold)); \
58    EXPECT_NEAR((c), (transform).matrix().get(0, 2), (errorThreshold)); \
59    EXPECT_NEAR((d), (transform).matrix().get(0, 3), (errorThreshold));
60
61#define EXPECT_ROW2_NEAR(a, b, c, d, transform, errorThreshold)         \
62    EXPECT_NEAR((a), (transform).matrix().get(1, 0), (errorThreshold)); \
63    EXPECT_NEAR((b), (transform).matrix().get(1, 1), (errorThreshold)); \
64    EXPECT_NEAR((c), (transform).matrix().get(1, 2), (errorThreshold)); \
65    EXPECT_NEAR((d), (transform).matrix().get(1, 3), (errorThreshold));
66
67#define EXPECT_ROW3_NEAR(a, b, c, d, transform, errorThreshold)         \
68    EXPECT_NEAR((a), (transform).matrix().get(2, 0), (errorThreshold)); \
69    EXPECT_NEAR((b), (transform).matrix().get(2, 1), (errorThreshold)); \
70    EXPECT_NEAR((c), (transform).matrix().get(2, 2), (errorThreshold)); \
71    EXPECT_NEAR((d), (transform).matrix().get(2, 3), (errorThreshold));
72
73bool PointsAreNearlyEqual(const Point3F& lhs,
74                          const Point3F& rhs) {
75  float epsilon = 0.0001f;
76  return lhs.SquaredDistanceTo(rhs) < epsilon;
77}
78
79bool MatricesAreNearlyEqual(const Transform& lhs,
80                            const Transform& rhs) {
81  float epsilon = 0.0001f;
82  for (int row = 0; row < 4; ++row) {
83    for (int col = 0; col < 4; ++col) {
84      if (std::abs(lhs.matrix().get(row, col) -
85                   rhs.matrix().get(row, col)) > epsilon)
86        return false;
87    }
88  }
89  return true;
90}
91
92void InitializeTestMatrix(Transform* transform) {
93  SkMatrix44& matrix = transform->matrix();
94  matrix.set(0, 0, 10.f);
95  matrix.set(1, 0, 11.f);
96  matrix.set(2, 0, 12.f);
97  matrix.set(3, 0, 13.f);
98  matrix.set(0, 1, 14.f);
99  matrix.set(1, 1, 15.f);
100  matrix.set(2, 1, 16.f);
101  matrix.set(3, 1, 17.f);
102  matrix.set(0, 2, 18.f);
103  matrix.set(1, 2, 19.f);
104  matrix.set(2, 2, 20.f);
105  matrix.set(3, 2, 21.f);
106  matrix.set(0, 3, 22.f);
107  matrix.set(1, 3, 23.f);
108  matrix.set(2, 3, 24.f);
109  matrix.set(3, 3, 25.f);
110
111  // Sanity check
112  EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, (*transform));
113  EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, (*transform));
114  EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, (*transform));
115  EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, (*transform));
116}
117
118void InitializeTestMatrix2(Transform* transform) {
119  SkMatrix44& matrix = transform->matrix();
120  matrix.set(0, 0, 30.f);
121  matrix.set(1, 0, 31.f);
122  matrix.set(2, 0, 32.f);
123  matrix.set(3, 0, 33.f);
124  matrix.set(0, 1, 34.f);
125  matrix.set(1, 1, 35.f);
126  matrix.set(2, 1, 36.f);
127  matrix.set(3, 1, 37.f);
128  matrix.set(0, 2, 38.f);
129  matrix.set(1, 2, 39.f);
130  matrix.set(2, 2, 40.f);
131  matrix.set(3, 2, 41.f);
132  matrix.set(0, 3, 42.f);
133  matrix.set(1, 3, 43.f);
134  matrix.set(2, 3, 44.f);
135  matrix.set(3, 3, 45.f);
136
137  // Sanity check
138  EXPECT_ROW1_EQ(30.0f, 34.0f, 38.0f, 42.0f, (*transform));
139  EXPECT_ROW2_EQ(31.0f, 35.0f, 39.0f, 43.0f, (*transform));
140  EXPECT_ROW3_EQ(32.0f, 36.0f, 40.0f, 44.0f, (*transform));
141  EXPECT_ROW4_EQ(33.0f, 37.0f, 41.0f, 45.0f, (*transform));
142}
143
144const SkMScalar kApproxZero =
145    SkFloatToMScalar(std::numeric_limits<float>::epsilon());
146const SkMScalar kApproxOne = 1 - kApproxZero;
147
148void InitializeApproxIdentityMatrix(Transform* transform) {
149  SkMatrix44& matrix = transform->matrix();
150  matrix.set(0, 0, kApproxOne);
151  matrix.set(0, 1, kApproxZero);
152  matrix.set(0, 2, kApproxZero);
153  matrix.set(0, 3, kApproxZero);
154
155  matrix.set(1, 0, kApproxZero);
156  matrix.set(1, 1, kApproxOne);
157  matrix.set(1, 2, kApproxZero);
158  matrix.set(1, 3, kApproxZero);
159
160  matrix.set(2, 0, kApproxZero);
161  matrix.set(2, 1, kApproxZero);
162  matrix.set(2, 2, kApproxOne);
163  matrix.set(2, 3, kApproxZero);
164
165  matrix.set(3, 0, kApproxZero);
166  matrix.set(3, 1, kApproxZero);
167  matrix.set(3, 2, kApproxZero);
168  matrix.set(3, 3, kApproxOne);
169}
170
171#ifdef SK_MSCALAR_IS_DOUBLE
172#define ERROR_THRESHOLD 1e-14
173#else
174#define ERROR_THRESHOLD 1e-7
175#endif
176#define LOOSE_ERROR_THRESHOLD 1e-7
177
178TEST(XFormTest, Equality) {
179  Transform lhs, rhs, interpolated;
180  rhs.matrix().set3x3(1, 2, 3,
181                      4, 5, 6,
182                      7, 8, 9);
183  interpolated = lhs;
184  for (int i = 0; i <= 100; ++i) {
185    for (int row = 0; row < 4; ++row) {
186      for (int col = 0; col < 4; ++col) {
187        float a = lhs.matrix().get(row, col);
188        float b = rhs.matrix().get(row, col);
189        float t = i / 100.0f;
190        interpolated.matrix().set(row, col, a + (b - a) * t);
191      }
192    }
193    if (i == 100) {
194      EXPECT_TRUE(rhs == interpolated);
195    } else {
196      EXPECT_TRUE(rhs != interpolated);
197    }
198  }
199  lhs = Transform();
200  rhs = Transform();
201  for (int i = 1; i < 100; ++i) {
202    lhs.MakeIdentity();
203    rhs.MakeIdentity();
204    lhs.Translate(i, i);
205    rhs.Translate(-i, -i);
206    EXPECT_TRUE(lhs != rhs);
207    rhs.Translate(2*i, 2*i);
208    EXPECT_TRUE(lhs == rhs);
209  }
210}
211
212TEST(XFormTest, ConcatTranslate) {
213  static const struct TestCase {
214    int x1;
215    int y1;
216    float tx;
217    float ty;
218    int x2;
219    int y2;
220  } test_cases[] = {
221    { 0, 0, 10.0f, 20.0f, 10, 20 },
222    { 0, 0, -10.0f, -20.0f, 0, 0 },
223    { 0, 0, -10.0f, -20.0f, -10, -20 },
224    { 0, 0,
225      std::numeric_limits<float>::quiet_NaN(),
226      std::numeric_limits<float>::quiet_NaN(),
227      10, 20 },
228  };
229
230  Transform xform;
231  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
232    const TestCase& value = test_cases[i];
233    Transform translation;
234    translation.Translate(value.tx, value.ty);
235    xform = translation * xform;
236    Point3F p1(value.x1, value.y1, 0);
237    Point3F p2(value.x2, value.y2, 0);
238    xform.TransformPoint(&p1);
239    if (value.tx == value.tx &&
240        value.ty == value.ty) {
241      EXPECT_TRUE(PointsAreNearlyEqual(p1, p2));
242    }
243  }
244}
245
246TEST(XFormTest, ConcatScale) {
247  static const struct TestCase {
248    int before;
249    float scale;
250    int after;
251  } test_cases[] = {
252    { 1, 10.0f, 10 },
253    { 1, .1f, 1 },
254    { 1, 100.0f, 100 },
255    { 1, -1.0f, -100 },
256    { 1, std::numeric_limits<float>::quiet_NaN(), 1 }
257  };
258
259  Transform xform;
260  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
261    const TestCase& value = test_cases[i];
262    Transform scale;
263    scale.Scale(value.scale, value.scale);
264    xform = scale * xform;
265    Point3F p1(value.before, value.before, 0);
266    Point3F p2(value.after, value.after, 0);
267    xform.TransformPoint(&p1);
268    if (value.scale == value.scale) {
269      EXPECT_TRUE(PointsAreNearlyEqual(p1, p2));
270    }
271  }
272}
273
274TEST(XFormTest, ConcatRotate) {
275  static const struct TestCase {
276    int x1;
277    int y1;
278    float degrees;
279    int x2;
280    int y2;
281  } test_cases[] = {
282    { 1, 0, 90.0f, 0, 1 },
283    { 1, 0, -90.0f, 1, 0 },
284    { 1, 0, 90.0f, 0, 1 },
285    { 1, 0, 360.0f, 0, 1 },
286    { 1, 0, 0.0f, 0, 1 },
287    { 1, 0, std::numeric_limits<float>::quiet_NaN(), 1, 0 }
288  };
289
290  Transform xform;
291  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
292    const TestCase& value = test_cases[i];
293    Transform rotation;
294    rotation.Rotate(value.degrees);
295    xform = rotation * xform;
296    Point3F p1(value.x1, value.y1, 0);
297    Point3F p2(value.x2, value.y2, 0);
298    xform.TransformPoint(&p1);
299    if (value.degrees == value.degrees) {
300      EXPECT_TRUE(PointsAreNearlyEqual(p1, p2));
301    }
302  }
303}
304
305TEST(XFormTest, SetTranslate) {
306  static const struct TestCase {
307    int x1; int y1;
308    float tx; float ty;
309    int x2; int y2;
310  } test_cases[] = {
311    { 0, 0, 10.0f, 20.0f, 10, 20 },
312    { 10, 20, 10.0f, 20.0f, 20, 40 },
313    { 10, 20, 0.0f, 0.0f, 10, 20 },
314    { 0, 0,
315      std::numeric_limits<float>::quiet_NaN(),
316      std::numeric_limits<float>::quiet_NaN(),
317      0, 0 }
318  };
319
320  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
321    const TestCase& value = test_cases[i];
322    for (int k = 0; k < 3; ++k) {
323      Point3F p0, p1, p2;
324      Transform xform;
325      switch (k) {
326      case 0:
327        p1.SetPoint(value.x1, 0, 0);
328        p2.SetPoint(value.x2, 0, 0);
329        xform.Translate(value.tx, 0.0);
330        break;
331      case 1:
332        p1.SetPoint(0, value.y1, 0);
333        p2.SetPoint(0, value.y2, 0);
334        xform.Translate(0.0, value.ty);
335        break;
336      case 2:
337        p1.SetPoint(value.x1, value.y1, 0);
338        p2.SetPoint(value.x2, value.y2, 0);
339        xform.Translate(value.tx, value.ty);
340        break;
341      }
342      p0 = p1;
343      xform.TransformPoint(&p1);
344      if (value.tx == value.tx &&
345          value.ty == value.ty) {
346        EXPECT_TRUE(PointsAreNearlyEqual(p1, p2));
347        xform.TransformPointReverse(&p1);
348        EXPECT_TRUE(PointsAreNearlyEqual(p1, p0));
349      }
350    }
351  }
352}
353
354TEST(XFormTest, SetScale) {
355  static const struct TestCase {
356    int before;
357    float s;
358    int after;
359  } test_cases[] = {
360    { 1, 10.0f, 10 },
361    { 1, 1.0f, 1 },
362    { 1, 0.0f, 0 },
363    { 0, 10.0f, 0 },
364    { 1, std::numeric_limits<float>::quiet_NaN(), 0 },
365  };
366
367  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
368    const TestCase& value = test_cases[i];
369    for (int k = 0; k < 3; ++k) {
370      Point3F p0, p1, p2;
371      Transform xform;
372      switch (k) {
373      case 0:
374        p1.SetPoint(value.before, 0, 0);
375        p2.SetPoint(value.after, 0, 0);
376        xform.Scale(value.s, 1.0);
377        break;
378      case 1:
379        p1.SetPoint(0, value.before, 0);
380        p2.SetPoint(0, value.after, 0);
381        xform.Scale(1.0, value.s);
382        break;
383      case 2:
384        p1.SetPoint(value.before, value.before, 0);
385        p2.SetPoint(value.after, value.after, 0);
386        xform.Scale(value.s, value.s);
387        break;
388      }
389      p0 = p1;
390      xform.TransformPoint(&p1);
391      if (value.s == value.s) {
392        EXPECT_TRUE(PointsAreNearlyEqual(p1, p2));
393        if (value.s != 0.0f) {
394          xform.TransformPointReverse(&p1);
395          EXPECT_TRUE(PointsAreNearlyEqual(p1, p0));
396        }
397      }
398    }
399  }
400}
401
402TEST(XFormTest, SetRotate) {
403  static const struct SetRotateCase {
404    int x;
405    int y;
406    float degree;
407    int xprime;
408    int yprime;
409  } set_rotate_cases[] = {
410    { 100, 0, 90.0f, 0, 100 },
411    { 0, 0, 90.0f, 0, 0 },
412    { 0, 100, 90.0f, -100, 0 },
413    { 0, 1, -90.0f, 1, 0 },
414    { 100, 0, 0.0f, 100, 0 },
415    { 0, 0, 0.0f, 0, 0 },
416    { 0, 0, std::numeric_limits<float>::quiet_NaN(), 0, 0 },
417    { 100, 0, 360.0f, 100, 0 }
418  };
419
420  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(set_rotate_cases); ++i) {
421    const SetRotateCase& value = set_rotate_cases[i];
422    Point3F p0;
423    Point3F p1(value.x, value.y, 0);
424    Point3F p2(value.xprime, value.yprime, 0);
425    p0 = p1;
426    Transform xform;
427    xform.Rotate(value.degree);
428    // just want to make sure that we don't crash in the case of NaN.
429    if (value.degree == value.degree) {
430      xform.TransformPoint(&p1);
431      EXPECT_TRUE(PointsAreNearlyEqual(p1, p2));
432      xform.TransformPointReverse(&p1);
433      EXPECT_TRUE(PointsAreNearlyEqual(p1, p0));
434    }
435  }
436}
437
438// 2D tests
439TEST(XFormTest, ConcatTranslate2D) {
440  static const struct TestCase {
441    int x1;
442    int y1;
443    float tx;
444    float ty;
445    int x2;
446    int y2;
447  } test_cases[] = {
448    { 0, 0, 10.0f, 20.0f, 10, 20},
449    { 0, 0, -10.0f, -20.0f, 0, 0},
450    { 0, 0, -10.0f, -20.0f, -10, -20},
451    { 0, 0,
452      std::numeric_limits<float>::quiet_NaN(),
453      std::numeric_limits<float>::quiet_NaN(),
454      10, 20},
455  };
456
457  Transform xform;
458  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
459    const TestCase& value = test_cases[i];
460    Transform translation;
461    translation.Translate(value.tx, value.ty);
462    xform = translation * xform;
463    Point p1(value.x1, value.y1);
464    Point p2(value.x2, value.y2);
465    xform.TransformPoint(&p1);
466    if (value.tx == value.tx &&
467        value.ty == value.ty) {
468      EXPECT_EQ(p1.x(), p2.x());
469      EXPECT_EQ(p1.y(), p2.y());
470    }
471  }
472}
473
474TEST(XFormTest, ConcatScale2D) {
475  static const struct TestCase {
476    int before;
477    float scale;
478    int after;
479  } test_cases[] = {
480    { 1, 10.0f, 10},
481    { 1, .1f, 1},
482    { 1, 100.0f, 100},
483    { 1, -1.0f, -100},
484    { 1, std::numeric_limits<float>::quiet_NaN(), 1}
485  };
486
487  Transform xform;
488  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
489    const TestCase& value = test_cases[i];
490    Transform scale;
491    scale.Scale(value.scale, value.scale);
492    xform = scale * xform;
493    Point p1(value.before, value.before);
494    Point p2(value.after, value.after);
495    xform.TransformPoint(&p1);
496    if (value.scale == value.scale) {
497      EXPECT_EQ(p1.x(), p2.x());
498      EXPECT_EQ(p1.y(), p2.y());
499    }
500  }
501}
502
503TEST(XFormTest, ConcatRotate2D) {
504  static const struct TestCase {
505    int x1;
506    int y1;
507    float degrees;
508    int x2;
509    int y2;
510  } test_cases[] = {
511    { 1, 0, 90.0f, 0, 1},
512    { 1, 0, -90.0f, 1, 0},
513    { 1, 0, 90.0f, 0, 1},
514    { 1, 0, 360.0f, 0, 1},
515    { 1, 0, 0.0f, 0, 1},
516    { 1, 0, std::numeric_limits<float>::quiet_NaN(), 1, 0}
517  };
518
519  Transform xform;
520  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
521    const TestCase& value = test_cases[i];
522    Transform rotation;
523    rotation.Rotate(value.degrees);
524    xform = rotation * xform;
525    Point p1(value.x1, value.y1);
526    Point p2(value.x2, value.y2);
527    xform.TransformPoint(&p1);
528    if (value.degrees == value.degrees) {
529      EXPECT_EQ(p1.x(), p2.x());
530      EXPECT_EQ(p1.y(), p2.y());
531    }
532  }
533}
534
535TEST(XFormTest, SetTranslate2D) {
536  static const struct TestCase {
537    int x1; int y1;
538    float tx; float ty;
539    int x2; int y2;
540  } test_cases[] = {
541    { 0, 0, 10.0f, 20.0f, 10, 20},
542    { 10, 20, 10.0f, 20.0f, 20, 40},
543    { 10, 20, 0.0f, 0.0f, 10, 20},
544    { 0, 0,
545      std::numeric_limits<float>::quiet_NaN(),
546      std::numeric_limits<float>::quiet_NaN(),
547      0, 0}
548  };
549
550  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
551    const TestCase& value = test_cases[i];
552    for (int j = -1; j < 2; ++j) {
553      for (int k = 0; k < 3; ++k) {
554        float epsilon = 0.0001f;
555        Point p0, p1, p2;
556        Transform xform;
557        switch (k) {
558        case 0:
559          p1.SetPoint(value.x1, 0);
560          p2.SetPoint(value.x2, 0);
561          xform.Translate(value.tx + j * epsilon, 0.0);
562          break;
563        case 1:
564          p1.SetPoint(0, value.y1);
565          p2.SetPoint(0, value.y2);
566          xform.Translate(0.0, value.ty + j * epsilon);
567          break;
568        case 2:
569          p1.SetPoint(value.x1, value.y1);
570          p2.SetPoint(value.x2, value.y2);
571          xform.Translate(value.tx + j * epsilon,
572                          value.ty + j * epsilon);
573          break;
574        }
575        p0 = p1;
576        xform.TransformPoint(&p1);
577        if (value.tx == value.tx &&
578            value.ty == value.ty) {
579          EXPECT_EQ(p1.x(), p2.x());
580          EXPECT_EQ(p1.y(), p2.y());
581          xform.TransformPointReverse(&p1);
582          EXPECT_EQ(p1.x(), p0.x());
583          EXPECT_EQ(p1.y(), p0.y());
584        }
585      }
586    }
587  }
588}
589
590TEST(XFormTest, SetScale2D) {
591  static const struct TestCase {
592    int before;
593    float s;
594    int after;
595  } test_cases[] = {
596    { 1, 10.0f, 10},
597    { 1, 1.0f, 1},
598    { 1, 0.0f, 0},
599    { 0, 10.0f, 0},
600    { 1, std::numeric_limits<float>::quiet_NaN(), 0},
601  };
602
603  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
604    const TestCase& value = test_cases[i];
605    for (int j = -1; j < 2; ++j) {
606      for (int k = 0; k < 3; ++k) {
607        float epsilon = 0.0001f;
608        Point p0, p1, p2;
609        Transform xform;
610        switch (k) {
611        case 0:
612          p1.SetPoint(value.before, 0);
613          p2.SetPoint(value.after, 0);
614          xform.Scale(value.s + j * epsilon, 1.0);
615          break;
616        case 1:
617          p1.SetPoint(0, value.before);
618          p2.SetPoint(0, value.after);
619          xform.Scale(1.0, value.s + j * epsilon);
620          break;
621        case 2:
622          p1.SetPoint(value.before,
623                      value.before);
624          p2.SetPoint(value.after,
625                      value.after);
626          xform.Scale(value.s + j * epsilon,
627                      value.s + j * epsilon);
628          break;
629        }
630        p0 = p1;
631        xform.TransformPoint(&p1);
632        if (value.s == value.s) {
633          EXPECT_EQ(p1.x(), p2.x());
634          EXPECT_EQ(p1.y(), p2.y());
635          if (value.s != 0.0f) {
636            xform.TransformPointReverse(&p1);
637            EXPECT_EQ(p1.x(), p0.x());
638            EXPECT_EQ(p1.y(), p0.y());
639          }
640        }
641      }
642    }
643  }
644}
645
646TEST(XFormTest, SetRotate2D) {
647  static const struct SetRotateCase {
648    int x;
649    int y;
650    float degree;
651    int xprime;
652    int yprime;
653  } set_rotate_cases[] = {
654    { 100, 0, 90.0f, 0, 100},
655    { 0, 0, 90.0f, 0, 0},
656    { 0, 100, 90.0f, -100, 0},
657    { 0, 1, -90.0f, 1, 0},
658    { 100, 0, 0.0f, 100, 0},
659    { 0, 0, 0.0f, 0, 0},
660    { 0, 0, std::numeric_limits<float>::quiet_NaN(), 0, 0},
661    { 100, 0, 360.0f, 100, 0}
662  };
663
664  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(set_rotate_cases); ++i) {
665    const SetRotateCase& value = set_rotate_cases[i];
666    for (int j = 1; j >= -1; --j) {
667      float epsilon = 0.1f;
668      Point pt(value.x, value.y);
669      Transform xform;
670      // should be invariant to small floating point errors.
671      xform.Rotate(value.degree + j * epsilon);
672      // just want to make sure that we don't crash in the case of NaN.
673      if (value.degree == value.degree) {
674        xform.TransformPoint(&pt);
675        EXPECT_EQ(value.xprime, pt.x());
676        EXPECT_EQ(value.yprime, pt.y());
677        xform.TransformPointReverse(&pt);
678        EXPECT_EQ(pt.x(), value.x);
679        EXPECT_EQ(pt.y(), value.y);
680      }
681    }
682  }
683}
684
685TEST(XFormTest, TransformPointWithExtremePerspective) {
686  Point3F point(1.f, 1.f, 1.f);
687  Transform perspective;
688  perspective.ApplyPerspectiveDepth(1.f);
689  Point3F transformed = point;
690  perspective.TransformPoint(&transformed);
691  EXPECT_EQ(point.ToString(), transformed.ToString());
692
693  transformed = point;
694  perspective.MakeIdentity();
695  perspective.ApplyPerspectiveDepth(1.1f);
696  perspective.TransformPoint(&transformed);
697  EXPECT_FLOAT_EQ(11.f, transformed.x());
698  EXPECT_FLOAT_EQ(11.f, transformed.y());
699  EXPECT_FLOAT_EQ(11.f, transformed.z());
700}
701
702TEST(XFormTest, BlendTranslate) {
703  Transform from;
704  for (int i = -5; i < 15; ++i) {
705    Transform to;
706    to.Translate3d(1, 1, 1);
707    double t = i / 9.0;
708    EXPECT_TRUE(to.Blend(from, t));
709    EXPECT_FLOAT_EQ(t, to.matrix().get(0, 3));
710    EXPECT_FLOAT_EQ(t, to.matrix().get(1, 3));
711    EXPECT_FLOAT_EQ(t, to.matrix().get(2, 3));
712  }
713}
714
715TEST(XFormTest, BlendRotate) {
716  Vector3dF axes[] = {
717    Vector3dF(1, 0, 0),
718    Vector3dF(0, 1, 0),
719    Vector3dF(0, 0, 1),
720    Vector3dF(1, 1, 1)
721  };
722  Transform from;
723  for (size_t index = 0; index < ARRAYSIZE_UNSAFE(axes); ++index) {
724    for (int i = -5; i < 15; ++i) {
725      Transform to;
726      to.RotateAbout(axes[index], 90);
727      double t = i / 9.0;
728      EXPECT_TRUE(to.Blend(from, t));
729
730      Transform expected;
731      expected.RotateAbout(axes[index], 90 * t);
732
733      EXPECT_TRUE(MatricesAreNearlyEqual(expected, to));
734    }
735  }
736}
737
738#if defined(_WIN64)
739// http://crbug.com/406574
740#define MAYBE_BlendRotateFollowsShortestPath DISABLED_BlendRotateFollowsShortestPath
741#else
742#define MAYBE_BlendRotateFollowsShortestPath BlendRotateFollowsShortestPath
743#endif
744TEST(XFormTest, MAYBE_BlendRotateFollowsShortestPath) {
745  // Verify that we interpolate along the shortest path regardless of whether
746  // this path crosses the 180-degree point.
747  Vector3dF axes[] = {
748    Vector3dF(1, 0, 0),
749    Vector3dF(0, 1, 0),
750    Vector3dF(0, 0, 1),
751    Vector3dF(1, 1, 1)
752  };
753  for (size_t index = 0; index < ARRAYSIZE_UNSAFE(axes); ++index) {
754    for (int i = -5; i < 15; ++i) {
755      Transform from1;
756      from1.RotateAbout(axes[index], 130.0);
757      Transform to1;
758      to1.RotateAbout(axes[index], 175.0);
759
760      Transform from2;
761      from2.RotateAbout(axes[index], 140.0);
762      Transform to2;
763      to2.RotateAbout(axes[index], 185.0);
764
765      double t = i / 9.0;
766      EXPECT_TRUE(to1.Blend(from1, t));
767      EXPECT_TRUE(to2.Blend(from2, t));
768
769      Transform expected1;
770      expected1.RotateAbout(axes[index], 130.0 + 45.0 * t);
771
772      Transform expected2;
773      expected2.RotateAbout(axes[index], 140.0 + 45.0 * t);
774
775      EXPECT_TRUE(MatricesAreNearlyEqual(expected1, to1));
776      EXPECT_TRUE(MatricesAreNearlyEqual(expected2, to2));
777    }
778  }
779}
780
781TEST(XFormTest, CanBlend180DegreeRotation) {
782  Vector3dF axes[] = {
783    Vector3dF(1, 0, 0),
784    Vector3dF(0, 1, 0),
785    Vector3dF(0, 0, 1),
786    Vector3dF(1, 1, 1)
787  };
788  Transform from;
789  for (size_t index = 0; index < ARRAYSIZE_UNSAFE(axes); ++index) {
790    for (int i = -5; i < 15; ++i) {
791      Transform to;
792      to.RotateAbout(axes[index], 180.0);
793      double t = i / 9.0;
794      EXPECT_TRUE(to.Blend(from, t));
795
796      // A 180 degree rotation is exactly opposite on the sphere, therefore
797      // either great circle arc to it is equivalent (and numerical precision
798      // will determine which is closer).  Test both directions.
799      Transform expected1;
800      expected1.RotateAbout(axes[index], 180.0 * t);
801      Transform expected2;
802      expected2.RotateAbout(axes[index], -180.0 * t);
803
804      EXPECT_TRUE(MatricesAreNearlyEqual(expected1, to) ||
805                  MatricesAreNearlyEqual(expected2, to))
806          << "axis: " << index << ", i: " << i;
807    }
808  }
809}
810
811#if defined(_WIN64)
812// http://crbug.com/406574
813#define MAYBE_BlendScale DISABLED_BlendScale
814#else
815#define MAYBE_BlendScale BlendScale
816#endif
817TEST(XFormTest, MAYBE_BlendScale) {
818  Transform from;
819  for (int i = -5; i < 15; ++i) {
820    Transform to;
821    to.Scale3d(5, 4, 3);
822    double t = i / 9.0;
823    EXPECT_TRUE(to.Blend(from, t));
824    EXPECT_FLOAT_EQ(t * 4 + 1, to.matrix().get(0, 0)) << "i: " << i;
825    EXPECT_FLOAT_EQ(t * 3 + 1, to.matrix().get(1, 1)) << "i: " << i;
826    EXPECT_FLOAT_EQ(t * 2 + 1, to.matrix().get(2, 2)) << "i: " << i;
827  }
828}
829
830TEST(XFormTest, BlendSkew) {
831  Transform from;
832  for (int i = 0; i < 2; ++i) {
833    Transform to;
834    to.SkewX(10);
835    to.SkewY(5);
836    double t = i;
837    Transform expected;
838    expected.SkewX(t * 10);
839    expected.SkewY(t * 5);
840    EXPECT_TRUE(to.Blend(from, t));
841    EXPECT_TRUE(MatricesAreNearlyEqual(expected, to));
842  }
843}
844
845TEST(XFormTest, ExtrapolateSkew) {
846  Transform from;
847  for (int i = -1; i < 2; ++i) {
848    Transform to;
849    to.SkewX(20);
850    double t = i;
851    Transform expected;
852    expected.SkewX(t * 20);
853    EXPECT_TRUE(to.Blend(from, t));
854    EXPECT_TRUE(MatricesAreNearlyEqual(expected, to));
855  }
856}
857
858#if defined(_WIN64)
859// http://crbug.com/406574
860#define MAYBE_BlendPerspective DISABLED_BlendPerspective
861#else
862#define MAYBE_BlendPerspective BlendPerspective
863#endif
864TEST(XFormTest, MAYBE_BlendPerspective) {
865  Transform from;
866  from.ApplyPerspectiveDepth(200);
867  for (int i = -1; i < 3; ++i) {
868    Transform to;
869    to.ApplyPerspectiveDepth(800);
870    double t = i;
871    double depth = 1.0 / ((1.0 / 200) * (1.0 - t) + (1.0 / 800) * t);
872    Transform expected;
873    expected.ApplyPerspectiveDepth(depth);
874    EXPECT_TRUE(to.Blend(from, t));
875    EXPECT_TRUE(MatricesAreNearlyEqual(expected, to));
876  }
877}
878
879TEST(XFormTest, BlendIdentity) {
880  Transform from;
881  Transform to;
882  EXPECT_TRUE(to.Blend(from, 0.5));
883  EXPECT_EQ(to, from);
884}
885
886TEST(XFormTest, CannotBlendSingularMatrix) {
887  Transform from;
888  Transform to;
889  to.matrix().set(1, 1, SkDoubleToMScalar(0));
890  EXPECT_FALSE(to.Blend(from, 0.5));
891}
892
893TEST(XFormTest, VerifyBlendForTranslation) {
894  Transform from;
895  from.Translate3d(100.0, 200.0, 100.0);
896
897  Transform to;
898
899  to.Translate3d(200.0, 100.0, 300.0);
900  to.Blend(from, 0.0);
901  EXPECT_EQ(from, to);
902
903  to = Transform();
904  to.Translate3d(200.0, 100.0, 300.0);
905  to.Blend(from, 0.25);
906  EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 125.0f, to);
907  EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 175.0f, to);
908  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 150.0f, to);
909  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f,  1.0f,  to);
910
911  to = Transform();
912  to.Translate3d(200.0, 100.0, 300.0);
913  to.Blend(from, 0.5);
914  EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 150.0f, to);
915  EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 150.0f, to);
916  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 200.0f, to);
917  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f,  1.0f,  to);
918
919  to = Transform();
920  to.Translate3d(200.0, 100.0, 300.0);
921  to.Blend(from, 1.0);
922  EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 200.0f, to);
923  EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 100.0f, to);
924  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 300.0f, to);
925  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f,  1.0f,  to);
926}
927
928TEST(XFormTest, VerifyBlendForScale) {
929  Transform from;
930  from.Scale3d(100.0, 200.0, 100.0);
931
932  Transform to;
933
934  to.Scale3d(200.0, 100.0, 300.0);
935  to.Blend(from, 0.0);
936  EXPECT_EQ(from, to);
937
938  to = Transform();
939  to.Scale3d(200.0, 100.0, 300.0);
940  to.Blend(from, 0.25);
941  EXPECT_ROW1_EQ(125.0f, 0.0f,  0.0f,  0.0f, to);
942  EXPECT_ROW2_EQ(0.0f,  175.0f, 0.0f,  0.0f, to);
943  EXPECT_ROW3_EQ(0.0f,   0.0f, 150.0f, 0.0f, to);
944  EXPECT_ROW4_EQ(0.0f,   0.0f,  0.0f,  1.0f, to);
945
946  to = Transform();
947  to.Scale3d(200.0, 100.0, 300.0);
948  to.Blend(from, 0.5);
949  EXPECT_ROW1_EQ(150.0f, 0.0f,  0.0f,  0.0f, to);
950  EXPECT_ROW2_EQ(0.0f,  150.0f, 0.0f,  0.0f, to);
951  EXPECT_ROW3_EQ(0.0f,   0.0f, 200.0f, 0.0f, to);
952  EXPECT_ROW4_EQ(0.0f,   0.0f,  0.0f,  1.0f, to);
953
954  to = Transform();
955  to.Scale3d(200.0, 100.0, 300.0);
956  to.Blend(from, 1.0);
957  EXPECT_ROW1_EQ(200.0f, 0.0f,  0.0f,  0.0f, to);
958  EXPECT_ROW2_EQ(0.0f,  100.0f, 0.0f,  0.0f, to);
959  EXPECT_ROW3_EQ(0.0f,   0.0f, 300.0f, 0.0f, to);
960  EXPECT_ROW4_EQ(0.0f,   0.0f,  0.0f,  1.0f, to);
961}
962
963TEST(XFormTest, VerifyBlendForSkewX) {
964  Transform from;
965  from.SkewX(0.0);
966
967  Transform to;
968
969  to.SkewX(45.0);
970  to.Blend(from, 0.0);
971  EXPECT_EQ(from, to);
972
973  to = Transform();
974  to.SkewX(45.0);
975  to.Blend(from, 0.5);
976  EXPECT_ROW1_EQ(1.0f, 0.5f, 0.0f, 0.0f, to);
977  EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, to);
978  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
979  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
980
981  to = Transform();
982  to.SkewX(45.0);
983  to.Blend(from, 0.25);
984  EXPECT_ROW1_EQ(1.0f, 0.25f, 0.0f, 0.0f, to);
985  EXPECT_ROW2_EQ(0.0f, 1.0f,  0.0f, 0.0f, to);
986  EXPECT_ROW3_EQ(0.0f, 0.0f,  1.0f, 0.0f, to);
987  EXPECT_ROW4_EQ(0.0f, 0.0f,  0.0f, 1.0f, to);
988
989  to = Transform();
990  to.SkewX(45.0);
991  to.Blend(from, 1.0);
992  EXPECT_ROW1_EQ(1.0f, 1.0f, 0.0f, 0.0f, to);
993  EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, to);
994  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
995  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
996}
997
998TEST(XFormTest, VerifyBlendForSkewY) {
999  // NOTE CAREFULLY: Decomposition of skew and rotation terms of the matrix
1000  // is inherently underconstrained, and so it does not always compute the
1001  // originally intended skew parameters. The current implementation uses QR
1002  // decomposition, which decomposes the shear into a rotation + non-uniform
1003  // scale.
1004  //
1005  // It is unlikely that the decomposition implementation will need to change
1006  // very often, so to get any test coverage, the compromise is to verify the
1007  // exact matrix that the.Blend() operation produces.
1008  //
1009  // This problem also potentially exists for skewX, but the current QR
1010  // decomposition implementation just happens to decompose those test
1011  // matrices intuitively.
1012  //
1013  // Unfortunately, this case suffers from uncomfortably large precision
1014  // error.
1015
1016  Transform from;
1017  from.SkewY(0.0);
1018
1019  Transform to;
1020
1021  to.SkewY(45.0);
1022  to.Blend(from, 0.0);
1023  EXPECT_EQ(from, to);
1024
1025  to = Transform();
1026  to.SkewY(45.0);
1027  to.Blend(from, 0.25);
1028  EXPECT_ROW1_NEAR(1.0823489449280947471976333,
1029                   0.0464370719145053845178239,
1030                   0.0,
1031                   0.0,
1032                   to,
1033                   LOOSE_ERROR_THRESHOLD);
1034  EXPECT_ROW2_NEAR(0.2152925909665224513123150,
1035                   0.9541702441750861130032035,
1036                   0.0,
1037                   0.0,
1038                   to,
1039                   LOOSE_ERROR_THRESHOLD);
1040  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
1041  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1042
1043  to = Transform();
1044  to.SkewY(45.0);
1045  to.Blend(from, 0.5);
1046  EXPECT_ROW1_NEAR(1.1152212925809066312865525,
1047                   0.0676495144007326631996335,
1048                   0.0,
1049                   0.0,
1050                   to,
1051                   LOOSE_ERROR_THRESHOLD);
1052  EXPECT_ROW2_NEAR(0.4619397844342648662419037,
1053                   0.9519009045724774464858342,
1054                   0.0,
1055                   0.0,
1056                   to,
1057                   LOOSE_ERROR_THRESHOLD);
1058  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
1059  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1060
1061  to = Transform();
1062  to.SkewY(45.0);
1063  to.Blend(from, 1.0);
1064  EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, LOOSE_ERROR_THRESHOLD);
1065  EXPECT_ROW2_NEAR(1.0, 1.0, 0.0, 0.0, to, LOOSE_ERROR_THRESHOLD);
1066  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
1067  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1068}
1069
1070#if defined(_WIN64)
1071// http://crbug.com/406574
1072#define MAYBE_VerifyBlendForRotationAboutX DISABLED_VerifyBlendForRotationAboutX
1073#else
1074#define MAYBE_VerifyBlendForRotationAboutX VerifyBlendForRotationAboutX
1075#endif
1076TEST(XFormTest, MAYBE_VerifyBlendForRotationAboutX) {
1077  // Even though.Blending uses quaternions, axis-aligned rotations should.
1078  // Blend the same with quaternions or Euler angles. So we can test
1079  // rotation.Blending by comparing against manually specified matrices from
1080  // Euler angles.
1081
1082  Transform from;
1083  from.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 0.0);
1084
1085  Transform to;
1086
1087  to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1088  to.Blend(from, 0.0);
1089  EXPECT_EQ(from, to);
1090
1091  double expectedRotationAngle = 22.5 * M_PI / 180.0;
1092  to = Transform();
1093  to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1094  to.Blend(from, 0.25);
1095  EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1096  EXPECT_ROW2_NEAR(0.0,
1097                   std::cos(expectedRotationAngle),
1098                   -std::sin(expectedRotationAngle),
1099                   0.0,
1100                   to,
1101                   ERROR_THRESHOLD);
1102  EXPECT_ROW3_NEAR(0.0,
1103                   std::sin(expectedRotationAngle),
1104                   std::cos(expectedRotationAngle),
1105                   0.0,
1106                   to,
1107                   ERROR_THRESHOLD);
1108  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1109
1110  expectedRotationAngle = 45.0 * M_PI / 180.0;
1111  to = Transform();
1112  to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1113  to.Blend(from, 0.5);
1114  EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1115  EXPECT_ROW2_NEAR(0.0,
1116                   std::cos(expectedRotationAngle),
1117                   -std::sin(expectedRotationAngle),
1118                   0.0,
1119                   to,
1120                   ERROR_THRESHOLD);
1121  EXPECT_ROW3_NEAR(0.0,
1122                   std::sin(expectedRotationAngle),
1123                   std::cos(expectedRotationAngle),
1124                   0.0,
1125                   to,
1126                   ERROR_THRESHOLD);
1127  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1128
1129  to = Transform();
1130  to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1131  to.Blend(from, 1.0);
1132  EXPECT_ROW1_NEAR(1.0, 0.0,  0.0, 0.0, to, ERROR_THRESHOLD);
1133  EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, to, ERROR_THRESHOLD);
1134  EXPECT_ROW3_NEAR(0.0, 1.0,  0.0, 0.0, to, ERROR_THRESHOLD);
1135  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1136}
1137
1138#if defined(_WIN64)
1139// http://crbug.com/406574
1140#define MAYBE_VerifyBlendForRotationAboutY DISABLED_VerifyBlendForRotationAboutY
1141#else
1142#define MAYBE_VerifyBlendForRotationAboutY VerifyBlendForRotationAboutY
1143#endif
1144TEST(XFormTest, MAYBE_VerifyBlendForRotationAboutY) {
1145  Transform from;
1146  from.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 0.0);
1147
1148  Transform to;
1149
1150  to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1151  to.Blend(from, 0.0);
1152  EXPECT_EQ(from, to);
1153
1154  double expectedRotationAngle = 22.5 * M_PI / 180.0;
1155  to = Transform();
1156  to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1157  to.Blend(from, 0.25);
1158  EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle),
1159                   0.0,
1160                   std::sin(expectedRotationAngle),
1161                   0.0,
1162                   to,
1163                   ERROR_THRESHOLD);
1164  EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1165  EXPECT_ROW3_NEAR(-std::sin(expectedRotationAngle),
1166                   0.0,
1167                   std::cos(expectedRotationAngle),
1168                   0.0,
1169                   to,
1170                   ERROR_THRESHOLD);
1171  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1172
1173  expectedRotationAngle = 45.0 * M_PI / 180.0;
1174  to = Transform();
1175  to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1176  to.Blend(from, 0.5);
1177  EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle),
1178                   0.0,
1179                   std::sin(expectedRotationAngle),
1180                   0.0,
1181                   to,
1182                   ERROR_THRESHOLD);
1183  EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1184  EXPECT_ROW3_NEAR(-std::sin(expectedRotationAngle),
1185                   0.0,
1186                   std::cos(expectedRotationAngle),
1187                   0.0,
1188                   to,
1189                   ERROR_THRESHOLD);
1190  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1191
1192  to = Transform();
1193  to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1194  to.Blend(from, 1.0);
1195  EXPECT_ROW1_NEAR(0.0,  0.0, 1.0, 0.0, to, ERROR_THRESHOLD);
1196  EXPECT_ROW2_NEAR(0.0,  1.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1197  EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1198  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1199}
1200
1201#if defined(_WIN64)
1202// http://crbug.com/406574
1203#define MAYBE_VerifyBlendForRotationAboutZ DISABLED_VerifyBlendForRotationAboutZ
1204#else
1205#define MAYBE_VerifyBlendForRotationAboutZ VerifyBlendForRotationAboutZ
1206#endif
1207TEST(XFormTest, MAYBE_VerifyBlendForRotationAboutZ) {
1208  Transform from;
1209  from.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 0.0);
1210
1211  Transform to;
1212
1213  to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1214  to.Blend(from, 0.0);
1215  EXPECT_EQ(from, to);
1216
1217  double expectedRotationAngle = 22.5 * M_PI / 180.0;
1218  to = Transform();
1219  to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1220  to.Blend(from, 0.25);
1221  EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle),
1222                   -std::sin(expectedRotationAngle),
1223                   0.0,
1224                   0.0,
1225                   to,
1226                   ERROR_THRESHOLD);
1227  EXPECT_ROW2_NEAR(std::sin(expectedRotationAngle),
1228                   std::cos(expectedRotationAngle),
1229                   0.0,
1230                   0.0,
1231                   to,
1232                   ERROR_THRESHOLD);
1233  EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to, ERROR_THRESHOLD);
1234  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1235
1236  expectedRotationAngle = 45.0 * M_PI / 180.0;
1237  to = Transform();
1238  to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1239  to.Blend(from, 0.5);
1240  EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle),
1241                   -std::sin(expectedRotationAngle),
1242                   0.0,
1243                   0.0,
1244                   to,
1245                   ERROR_THRESHOLD);
1246  EXPECT_ROW2_NEAR(std::sin(expectedRotationAngle),
1247                   std::cos(expectedRotationAngle),
1248                   0.0,
1249                   0.0,
1250                   to,
1251                   ERROR_THRESHOLD);
1252  EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to, ERROR_THRESHOLD);
1253  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1254
1255  to = Transform();
1256  to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1257  to.Blend(from, 1.0);
1258  EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1259  EXPECT_ROW2_NEAR(1.0,  0.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1260  EXPECT_ROW3_NEAR(0.0,  0.0, 1.0, 0.0, to, ERROR_THRESHOLD);
1261  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1262}
1263
1264TEST(XFormTest, VerifyBlendForCompositeTransform) {
1265  // Verify that the.Blending was done with a decomposition in correct order
1266  // by blending a composite transform. Using matrix x vector notation
1267  // (Ax = b, where x is column vector), the ordering should be:
1268  // perspective * translation * rotation * skew * scale
1269  //
1270  // It is not as important (or meaningful) to check intermediate
1271  // interpolations; order of operations will be tested well enough by the
1272  // end cases that are easier to specify.
1273
1274  Transform from;
1275  Transform to;
1276
1277  Transform expectedEndOfAnimation;
1278  expectedEndOfAnimation.ApplyPerspectiveDepth(1.0);
1279  expectedEndOfAnimation.Translate3d(10.0, 20.0, 30.0);
1280  expectedEndOfAnimation.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 25.0);
1281  expectedEndOfAnimation.SkewY(45.0);
1282  expectedEndOfAnimation.Scale3d(6.0, 7.0, 8.0);
1283
1284  to = expectedEndOfAnimation;
1285  to.Blend(from, 0.0);
1286  EXPECT_EQ(from, to);
1287
1288  to = expectedEndOfAnimation;
1289  // We short circuit if blend is >= 1, so to check the numerics, we will
1290  // check that we get close to what we expect when we're nearly done
1291  // interpolating.
1292  to.Blend(from, .99999f);
1293
1294  // Recomposing the matrix results in a normalized matrix, so to verify we
1295  // need to normalize the expectedEndOfAnimation before comparing elements.
1296  // Normalizing means dividing everything by expectedEndOfAnimation.m44().
1297  Transform normalizedExpectedEndOfAnimation = expectedEndOfAnimation;
1298  Transform normalizationMatrix;
1299  normalizationMatrix.matrix().set(
1300      0.0,
1301      0.0,
1302      SkDoubleToMScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0)));
1303  normalizationMatrix.matrix().set(
1304      1.0,
1305      1.0,
1306      SkDoubleToMScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0)));
1307  normalizationMatrix.matrix().set(
1308      2.0,
1309      2.0,
1310      SkDoubleToMScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0)));
1311  normalizationMatrix.matrix().set(
1312      3.0,
1313      3.0,
1314      SkDoubleToMScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0)));
1315  normalizedExpectedEndOfAnimation.PreconcatTransform(normalizationMatrix);
1316
1317  EXPECT_TRUE(MatricesAreNearlyEqual(normalizedExpectedEndOfAnimation, to));
1318}
1319
1320TEST(XFormTest, DecomposedTransformCtor) {
1321  DecomposedTransform decomp;
1322  for (int i = 0; i < 3; ++i) {
1323    EXPECT_EQ(0.0, decomp.translate[i]);
1324    EXPECT_EQ(1.0, decomp.scale[i]);
1325    EXPECT_EQ(0.0, decomp.skew[i]);
1326    EXPECT_EQ(0.0, decomp.quaternion[i]);
1327    EXPECT_EQ(0.0, decomp.perspective[i]);
1328  }
1329  EXPECT_EQ(1.0, decomp.quaternion[3]);
1330  EXPECT_EQ(1.0, decomp.perspective[3]);
1331  Transform identity;
1332  Transform composed = ComposeTransform(decomp);
1333  EXPECT_TRUE(MatricesAreNearlyEqual(identity, composed));
1334}
1335
1336TEST(XFormTest, FactorTRS) {
1337  for (int degrees = 0; degrees < 180; ++degrees) {
1338    // build a transformation matrix.
1339    gfx::Transform transform;
1340    transform.Translate(degrees * 2, -degrees * 3);
1341    transform.Rotate(degrees);
1342    transform.Scale(degrees + 1, 2 * degrees + 1);
1343
1344    // factor the matrix
1345    DecomposedTransform decomp;
1346    bool success = DecomposeTransform(&decomp, transform);
1347    EXPECT_TRUE(success);
1348    EXPECT_FLOAT_EQ(decomp.translate[0], degrees * 2);
1349    EXPECT_FLOAT_EQ(decomp.translate[1], -degrees * 3);
1350    double rotation =
1351        std::acos(SkMScalarToDouble(decomp.quaternion[3])) * 360.0 / M_PI;
1352    while (rotation < 0.0)
1353      rotation += 360.0;
1354    while (rotation > 360.0)
1355      rotation -= 360.0;
1356
1357    const float epsilon = 0.00015f;
1358    EXPECT_NEAR(rotation, degrees, epsilon);
1359    EXPECT_NEAR(decomp.scale[0], degrees + 1, epsilon);
1360    EXPECT_NEAR(decomp.scale[1], 2 * degrees + 1, epsilon);
1361  }
1362}
1363
1364TEST(XFormTest, IntegerTranslation) {
1365  gfx::Transform transform;
1366  EXPECT_TRUE(transform.IsIdentityOrIntegerTranslation());
1367
1368  transform.Translate3d(1, 2, 3);
1369  EXPECT_TRUE(transform.IsIdentityOrIntegerTranslation());
1370
1371  transform.MakeIdentity();
1372  transform.Translate3d(-1, -2, -3);
1373  EXPECT_TRUE(transform.IsIdentityOrIntegerTranslation());
1374
1375  transform.MakeIdentity();
1376  transform.Translate3d(4.5f, 0, 0);
1377  EXPECT_FALSE(transform.IsIdentityOrIntegerTranslation());
1378
1379  transform.MakeIdentity();
1380  transform.Translate3d(0, -6.7f, 0);
1381  EXPECT_FALSE(transform.IsIdentityOrIntegerTranslation());
1382
1383  transform.MakeIdentity();
1384  transform.Translate3d(0, 0, 8.9f);
1385  EXPECT_FALSE(transform.IsIdentityOrIntegerTranslation());
1386}
1387
1388TEST(XFormTest, verifyMatrixInversion) {
1389  {
1390    // Invert a translation
1391    gfx::Transform translation;
1392    translation.Translate3d(2.0, 3.0, 4.0);
1393    EXPECT_TRUE(translation.IsInvertible());
1394
1395    gfx::Transform inverse_translation;
1396    bool is_invertible = translation.GetInverse(&inverse_translation);
1397    EXPECT_TRUE(is_invertible);
1398    EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, -2.0f, inverse_translation);
1399    EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, -3.0f, inverse_translation);
1400    EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, -4.0f, inverse_translation);
1401    EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f,  1.0f, inverse_translation);
1402  }
1403
1404  {
1405    // Invert a non-uniform scale
1406    gfx::Transform scale;
1407    scale.Scale3d(4.0, 10.0, 100.0);
1408    EXPECT_TRUE(scale.IsInvertible());
1409
1410    gfx::Transform inverse_scale;
1411    bool is_invertible = scale.GetInverse(&inverse_scale);
1412    EXPECT_TRUE(is_invertible);
1413    EXPECT_ROW1_EQ(0.25f, 0.0f, 0.0f, 0.0f, inverse_scale);
1414    EXPECT_ROW2_EQ(0.0f,  0.1f, 0.0f, 0.0f, inverse_scale);
1415    EXPECT_ROW3_EQ(0.0f,  0.0f, 0.01f, 0.0f, inverse_scale);
1416    EXPECT_ROW4_EQ(0.0f,  0.0f, 0.0f, 1.0f, inverse_scale);
1417  }
1418
1419  {
1420    // Try to invert a matrix that is not invertible.
1421    // The inverse() function should reset the output matrix to identity.
1422    gfx::Transform uninvertible;
1423    uninvertible.matrix().set(0, 0, 0.f);
1424    uninvertible.matrix().set(1, 1, 0.f);
1425    uninvertible.matrix().set(2, 2, 0.f);
1426    uninvertible.matrix().set(3, 3, 0.f);
1427    EXPECT_FALSE(uninvertible.IsInvertible());
1428
1429    gfx::Transform inverse_of_uninvertible;
1430
1431    // Add a scale just to more easily ensure that inverse_of_uninvertible is
1432    // reset to identity.
1433    inverse_of_uninvertible.Scale3d(4.0, 10.0, 100.0);
1434
1435    bool is_invertible = uninvertible.GetInverse(&inverse_of_uninvertible);
1436    EXPECT_FALSE(is_invertible);
1437    EXPECT_TRUE(inverse_of_uninvertible.IsIdentity());
1438    EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, inverse_of_uninvertible);
1439    EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, inverse_of_uninvertible);
1440    EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, inverse_of_uninvertible);
1441    EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, inverse_of_uninvertible);
1442  }
1443}
1444
1445TEST(XFormTest, verifyBackfaceVisibilityBasicCases) {
1446  Transform transform;
1447
1448  transform.MakeIdentity();
1449  EXPECT_FALSE(transform.IsBackFaceVisible());
1450
1451  transform.MakeIdentity();
1452  transform.RotateAboutYAxis(80.0);
1453  EXPECT_FALSE(transform.IsBackFaceVisible());
1454
1455  transform.MakeIdentity();
1456  transform.RotateAboutYAxis(100.0);
1457  EXPECT_TRUE(transform.IsBackFaceVisible());
1458
1459  // Edge case, 90 degree rotation should return false.
1460  transform.MakeIdentity();
1461  transform.RotateAboutYAxis(90.0);
1462  EXPECT_FALSE(transform.IsBackFaceVisible());
1463}
1464
1465TEST(XFormTest, verifyBackfaceVisibilityForPerspective) {
1466  Transform layer_space_to_projection_plane;
1467
1468  // This tests if IsBackFaceVisible works properly under perspective
1469  // transforms.  Specifically, layers that may have their back face visible in
1470  // orthographic projection, may not actually have back face visible under
1471  // perspective projection.
1472
1473  // Case 1: Layer is rotated by slightly more than 90 degrees, at the center
1474  //         of the prespective projection. In this case, the layer's back-side
1475  //         is visible to the camera.
1476  layer_space_to_projection_plane.MakeIdentity();
1477  layer_space_to_projection_plane.ApplyPerspectiveDepth(1.0);
1478  layer_space_to_projection_plane.Translate3d(0.0, 0.0, 0.0);
1479  layer_space_to_projection_plane.RotateAboutYAxis(100.0);
1480  EXPECT_TRUE(layer_space_to_projection_plane.IsBackFaceVisible());
1481
1482  // Case 2: Layer is rotated by slightly more than 90 degrees, but shifted off
1483  //         to the side of the camera. Because of the wide field-of-view, the
1484  //         layer's front side is still visible.
1485  //
1486  //                       |<-- front side of layer is visible to camera
1487  //                    \  |            /
1488  //                     \ |           /
1489  //                      \|          /
1490  //                       |         /
1491  //                       |\       /<-- camera field of view
1492  //                       | \     /
1493  // back side of layer -->|  \   /
1494  //                           \./ <-- camera origin
1495  //
1496  layer_space_to_projection_plane.MakeIdentity();
1497  layer_space_to_projection_plane.ApplyPerspectiveDepth(1.0);
1498  layer_space_to_projection_plane.Translate3d(-10.0, 0.0, 0.0);
1499  layer_space_to_projection_plane.RotateAboutYAxis(100.0);
1500  EXPECT_FALSE(layer_space_to_projection_plane.IsBackFaceVisible());
1501
1502  // Case 3: Additionally rotating the layer by 180 degrees should of course
1503  //         show the opposite result of case 2.
1504  layer_space_to_projection_plane.RotateAboutYAxis(180.0);
1505  EXPECT_TRUE(layer_space_to_projection_plane.IsBackFaceVisible());
1506}
1507
1508TEST(XFormTest, verifyDefaultConstructorCreatesIdentityMatrix) {
1509  Transform A;
1510  EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1511  EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1512  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1513  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1514  EXPECT_TRUE(A.IsIdentity());
1515}
1516
1517TEST(XFormTest, verifyCopyConstructor) {
1518  Transform A;
1519  InitializeTestMatrix(&A);
1520
1521  // Copy constructor should produce exact same elements as matrix A.
1522  Transform B(A);
1523  EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, B);
1524  EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, B);
1525  EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, B);
1526  EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, B);
1527}
1528
1529TEST(XFormTest, verifyConstructorFor16Elements) {
1530  Transform transform(1.0, 2.0, 3.0, 4.0,
1531                      5.0, 6.0, 7.0, 8.0,
1532                      9.0, 10.0, 11.0, 12.0,
1533                      13.0, 14.0, 15.0, 16.0);
1534
1535  EXPECT_ROW1_EQ(1.0f, 2.0f, 3.0f, 4.0f, transform);
1536  EXPECT_ROW2_EQ(5.0f, 6.0f, 7.0f, 8.0f, transform);
1537  EXPECT_ROW3_EQ(9.0f, 10.0f, 11.0f, 12.0f, transform);
1538  EXPECT_ROW4_EQ(13.0f, 14.0f, 15.0f, 16.0f, transform);
1539}
1540
1541TEST(XFormTest, verifyConstructorFor2dElements) {
1542  Transform transform(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);
1543
1544  EXPECT_ROW1_EQ(1.0f, 2.0f, 0.0f, 5.0f, transform);
1545  EXPECT_ROW2_EQ(3.0f, 4.0f, 0.0f, 6.0f, transform);
1546  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, transform);
1547  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, transform);
1548}
1549
1550
1551TEST(XFormTest, verifyAssignmentOperator) {
1552  Transform A;
1553  InitializeTestMatrix(&A);
1554  Transform B;
1555  InitializeTestMatrix2(&B);
1556  Transform C;
1557  InitializeTestMatrix2(&C);
1558  C = B = A;
1559
1560  // Both B and C should now have been re-assigned to the value of A.
1561  EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, B);
1562  EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, B);
1563  EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, B);
1564  EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, B);
1565
1566  EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, C);
1567  EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, C);
1568  EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, C);
1569  EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, C);
1570}
1571
1572TEST(XFormTest, verifyEqualsBooleanOperator) {
1573  Transform A;
1574  InitializeTestMatrix(&A);
1575
1576  Transform B;
1577  InitializeTestMatrix(&B);
1578  EXPECT_TRUE(A == B);
1579
1580  // Modifying multiple elements should cause equals operator to return false.
1581  Transform C;
1582  InitializeTestMatrix2(&C);
1583  EXPECT_FALSE(A == C);
1584
1585  // Modifying any one individual element should cause equals operator to
1586  // return false.
1587  Transform D;
1588  D = A;
1589  D.matrix().set(0, 0, 0.f);
1590  EXPECT_FALSE(A == D);
1591
1592  D = A;
1593  D.matrix().set(1, 0, 0.f);
1594  EXPECT_FALSE(A == D);
1595
1596  D = A;
1597  D.matrix().set(2, 0, 0.f);
1598  EXPECT_FALSE(A == D);
1599
1600  D = A;
1601  D.matrix().set(3, 0, 0.f);
1602  EXPECT_FALSE(A == D);
1603
1604  D = A;
1605  D.matrix().set(0, 1, 0.f);
1606  EXPECT_FALSE(A == D);
1607
1608  D = A;
1609  D.matrix().set(1, 1, 0.f);
1610  EXPECT_FALSE(A == D);
1611
1612  D = A;
1613  D.matrix().set(2, 1, 0.f);
1614  EXPECT_FALSE(A == D);
1615
1616  D = A;
1617  D.matrix().set(3, 1, 0.f);
1618  EXPECT_FALSE(A == D);
1619
1620  D = A;
1621  D.matrix().set(0, 2, 0.f);
1622  EXPECT_FALSE(A == D);
1623
1624  D = A;
1625  D.matrix().set(1, 2, 0.f);
1626  EXPECT_FALSE(A == D);
1627
1628  D = A;
1629  D.matrix().set(2, 2, 0.f);
1630  EXPECT_FALSE(A == D);
1631
1632  D = A;
1633  D.matrix().set(3, 2, 0.f);
1634  EXPECT_FALSE(A == D);
1635
1636  D = A;
1637  D.matrix().set(0, 3, 0.f);
1638  EXPECT_FALSE(A == D);
1639
1640  D = A;
1641  D.matrix().set(1, 3, 0.f);
1642  EXPECT_FALSE(A == D);
1643
1644  D = A;
1645  D.matrix().set(2, 3, 0.f);
1646  EXPECT_FALSE(A == D);
1647
1648  D = A;
1649  D.matrix().set(3, 3, 0.f);
1650  EXPECT_FALSE(A == D);
1651}
1652
1653TEST(XFormTest, verifyMultiplyOperator) {
1654  Transform A;
1655  InitializeTestMatrix(&A);
1656
1657  Transform B;
1658  InitializeTestMatrix2(&B);
1659
1660  Transform C = A * B;
1661  EXPECT_ROW1_EQ(2036.0f, 2292.0f, 2548.0f, 2804.0f, C);
1662  EXPECT_ROW2_EQ(2162.0f, 2434.0f, 2706.0f, 2978.0f, C);
1663  EXPECT_ROW3_EQ(2288.0f, 2576.0f, 2864.0f, 3152.0f, C);
1664  EXPECT_ROW4_EQ(2414.0f, 2718.0f, 3022.0f, 3326.0f, C);
1665
1666  // Just an additional sanity check; matrix multiplication is not commutative.
1667  EXPECT_FALSE(A * B == B * A);
1668}
1669
1670TEST(XFormTest, verifyMultiplyAndAssignOperator) {
1671  Transform A;
1672  InitializeTestMatrix(&A);
1673
1674  Transform B;
1675  InitializeTestMatrix2(&B);
1676
1677  A *= B;
1678  EXPECT_ROW1_EQ(2036.0f, 2292.0f, 2548.0f, 2804.0f, A);
1679  EXPECT_ROW2_EQ(2162.0f, 2434.0f, 2706.0f, 2978.0f, A);
1680  EXPECT_ROW3_EQ(2288.0f, 2576.0f, 2864.0f, 3152.0f, A);
1681  EXPECT_ROW4_EQ(2414.0f, 2718.0f, 3022.0f, 3326.0f, A);
1682
1683  // Just an additional sanity check; matrix multiplication is not commutative.
1684  Transform C = A;
1685  C *= B;
1686  Transform D = B;
1687  D *= A;
1688  EXPECT_FALSE(C == D);
1689}
1690
1691TEST(XFormTest, verifyMatrixMultiplication) {
1692  Transform A;
1693  InitializeTestMatrix(&A);
1694
1695  Transform B;
1696  InitializeTestMatrix2(&B);
1697
1698  A.PreconcatTransform(B);
1699  EXPECT_ROW1_EQ(2036.0f, 2292.0f, 2548.0f, 2804.0f, A);
1700  EXPECT_ROW2_EQ(2162.0f, 2434.0f, 2706.0f, 2978.0f, A);
1701  EXPECT_ROW3_EQ(2288.0f, 2576.0f, 2864.0f, 3152.0f, A);
1702  EXPECT_ROW4_EQ(2414.0f, 2718.0f, 3022.0f, 3326.0f, A);
1703}
1704
1705TEST(XFormTest, verifyMakeIdentiy) {
1706  Transform A;
1707  InitializeTestMatrix(&A);
1708  A.MakeIdentity();
1709  EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1710  EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1711  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1712  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1713  EXPECT_TRUE(A.IsIdentity());
1714}
1715
1716TEST(XFormTest, verifyTranslate) {
1717  Transform A;
1718  A.Translate(2.0, 3.0);
1719  EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 2.0f, A);
1720  EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 3.0f, A);
1721  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1722  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1723
1724  // Verify that Translate() post-multiplies the existing matrix.
1725  A.MakeIdentity();
1726  A.Scale(5.0, 5.0);
1727  A.Translate(2.0, 3.0);
1728  EXPECT_ROW1_EQ(5.0f, 0.0f, 0.0f, 10.0f, A);
1729  EXPECT_ROW2_EQ(0.0f, 5.0f, 0.0f, 15.0f, A);
1730  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f,  A);
1731  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f,  A);
1732}
1733
1734TEST(XFormTest, verifyTranslate3d) {
1735  Transform A;
1736  A.Translate3d(2.0, 3.0, 4.0);
1737  EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 2.0f, A);
1738  EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 3.0f, A);
1739  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 4.0f, A);
1740  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1741
1742  // Verify that Translate3d() post-multiplies the existing matrix.
1743  A.MakeIdentity();
1744  A.Scale3d(6.0, 7.0, 8.0);
1745  A.Translate3d(2.0, 3.0, 4.0);
1746  EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 12.0f, A);
1747  EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 21.0f, A);
1748  EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 32.0f, A);
1749  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f,  A);
1750}
1751
1752TEST(XFormTest, verifyScale) {
1753  Transform A;
1754  A.Scale(6.0, 7.0);
1755  EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 0.0f, A);
1756  EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 0.0f, A);
1757  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1758  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1759
1760  // Verify that Scale() post-multiplies the existing matrix.
1761  A.MakeIdentity();
1762  A.Translate3d(2.0, 3.0, 4.0);
1763  A.Scale(6.0, 7.0);
1764  EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 2.0f, A);
1765  EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 3.0f, A);
1766  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 4.0f, A);
1767  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1768}
1769
1770TEST(XFormTest, verifyScale3d) {
1771  Transform A;
1772  A.Scale3d(6.0, 7.0, 8.0);
1773  EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 0.0f, A);
1774  EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 0.0f, A);
1775  EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
1776  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1777
1778  // Verify that scale3d() post-multiplies the existing matrix.
1779  A.MakeIdentity();
1780  A.Translate3d(2.0, 3.0, 4.0);
1781  A.Scale3d(6.0, 7.0, 8.0);
1782  EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 2.0f, A);
1783  EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 3.0f, A);
1784  EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 4.0f, A);
1785  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1786}
1787
1788TEST(XFormTest, verifyRotate) {
1789  Transform A;
1790  A.Rotate(90.0);
1791  EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1792  EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1793  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1794  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1795
1796  // Verify that Rotate() post-multiplies the existing matrix.
1797  A.MakeIdentity();
1798  A.Scale3d(6.0, 7.0, 8.0);
1799  A.Rotate(90.0);
1800  EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1801  EXPECT_ROW2_NEAR(7.0, 0.0,  0.0, 0.0, A, ERROR_THRESHOLD);
1802  EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
1803  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1804}
1805
1806TEST(XFormTest, verifyRotateAboutXAxis) {
1807  Transform A;
1808  double sin45 = 0.5 * sqrt(2.0);
1809  double cos45 = sin45;
1810
1811  A.MakeIdentity();
1812  A.RotateAboutXAxis(90.0);
1813  EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1814  EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, A, ERROR_THRESHOLD);
1815  EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1816  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1817
1818  A.MakeIdentity();
1819  A.RotateAboutXAxis(45.0);
1820  EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1821  EXPECT_ROW2_NEAR(0.0, cos45, -sin45, 0.0, A, ERROR_THRESHOLD);
1822  EXPECT_ROW3_NEAR(0.0, sin45, cos45, 0.0, A, ERROR_THRESHOLD);
1823  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1824
1825  // Verify that RotateAboutXAxis(angle) post-multiplies the existing matrix.
1826  A.MakeIdentity();
1827  A.Scale3d(6.0, 7.0, 8.0);
1828  A.RotateAboutXAxis(90.0);
1829  EXPECT_ROW1_NEAR(6.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1830  EXPECT_ROW2_NEAR(0.0, 0.0, -7.0, 0.0, A, ERROR_THRESHOLD);
1831  EXPECT_ROW3_NEAR(0.0, 8.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1832  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1833}
1834
1835TEST(XFormTest, verifyRotateAboutYAxis) {
1836  Transform A;
1837  double sin45 = 0.5 * sqrt(2.0);
1838  double cos45 = sin45;
1839
1840  // Note carefully, the expected pattern is inverted compared to rotating
1841  // about x axis or z axis.
1842  A.MakeIdentity();
1843  A.RotateAboutYAxis(90.0);
1844  EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, A, ERROR_THRESHOLD);
1845  EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1846  EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1847  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1848
1849  A.MakeIdentity();
1850  A.RotateAboutYAxis(45.0);
1851  EXPECT_ROW1_NEAR(cos45, 0.0, sin45, 0.0, A, ERROR_THRESHOLD);
1852  EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1853  EXPECT_ROW3_NEAR(-sin45, 0.0, cos45, 0.0, A, ERROR_THRESHOLD);
1854  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1855
1856  // Verify that RotateAboutYAxis(angle) post-multiplies the existing matrix.
1857  A.MakeIdentity();
1858  A.Scale3d(6.0, 7.0, 8.0);
1859  A.RotateAboutYAxis(90.0);
1860  EXPECT_ROW1_NEAR(0.0, 0.0, 6.0, 0.0, A, ERROR_THRESHOLD);
1861  EXPECT_ROW2_NEAR(0.0, 7.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1862  EXPECT_ROW3_NEAR(-8.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1863  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1864}
1865
1866TEST(XFormTest, verifyRotateAboutZAxis) {
1867  Transform A;
1868  double sin45 = 0.5 * sqrt(2.0);
1869  double cos45 = sin45;
1870
1871  A.MakeIdentity();
1872  A.RotateAboutZAxis(90.0);
1873  EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1874  EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1875  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1876  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1877
1878  A.MakeIdentity();
1879  A.RotateAboutZAxis(45.0);
1880  EXPECT_ROW1_NEAR(cos45, -sin45, 0.0, 0.0, A, ERROR_THRESHOLD);
1881  EXPECT_ROW2_NEAR(sin45, cos45, 0.0, 0.0, A, ERROR_THRESHOLD);
1882  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1883  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1884
1885  // Verify that RotateAboutZAxis(angle) post-multiplies the existing matrix.
1886  A.MakeIdentity();
1887  A.Scale3d(6.0, 7.0, 8.0);
1888  A.RotateAboutZAxis(90.0);
1889  EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1890  EXPECT_ROW2_NEAR(7.0, 0.0,  0.0, 0.0, A, ERROR_THRESHOLD);
1891  EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
1892  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1893}
1894
1895TEST(XFormTest, verifyRotateAboutForAlignedAxes) {
1896  Transform A;
1897
1898  // Check rotation about z-axis
1899  A.MakeIdentity();
1900  A.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1901  EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1902  EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1903  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1904  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1905
1906  // Check rotation about x-axis
1907  A.MakeIdentity();
1908  A.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1909  EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1910  EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, A, ERROR_THRESHOLD);
1911  EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1912  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1913
1914  // Check rotation about y-axis. Note carefully, the expected pattern is
1915  // inverted compared to rotating about x axis or z axis.
1916  A.MakeIdentity();
1917  A.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1918  EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, A, ERROR_THRESHOLD);
1919  EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1920  EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1921  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1922
1923  // Verify that rotate3d(axis, angle) post-multiplies the existing matrix.
1924  A.MakeIdentity();
1925  A.Scale3d(6.0, 7.0, 8.0);
1926  A.RotateAboutZAxis(90.0);
1927  EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1928  EXPECT_ROW2_NEAR(7.0, 0.0,  0.0, 0.0, A, ERROR_THRESHOLD);
1929  EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
1930  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1931}
1932
1933TEST(XFormTest, verifyRotateAboutForArbitraryAxis) {
1934  // Check rotation about an arbitrary non-axis-aligned vector.
1935  Transform A;
1936  A.RotateAbout(Vector3dF(1.0, 1.0, 1.0), 90.0);
1937  EXPECT_ROW1_NEAR(0.3333333333333334258519187,
1938                   -0.2440169358562924717404030,
1939                   0.9106836025229592124219380,
1940                   0.0, A, ERROR_THRESHOLD);
1941  EXPECT_ROW2_NEAR(0.9106836025229592124219380,
1942                   0.3333333333333334258519187,
1943                   -0.2440169358562924717404030,
1944                   0.0, A, ERROR_THRESHOLD);
1945  EXPECT_ROW3_NEAR(-0.2440169358562924717404030,
1946                   0.9106836025229592124219380,
1947                   0.3333333333333334258519187,
1948                   0.0, A, ERROR_THRESHOLD);
1949  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1950}
1951
1952TEST(XFormTest, verifyRotateAboutForDegenerateAxis) {
1953  // Check rotation about a degenerate zero vector.
1954  // It is expected to skip applying the rotation.
1955  Transform A;
1956
1957  A.RotateAbout(Vector3dF(0.0, 0.0, 0.0), 45.0);
1958  // Verify that A remains unchanged.
1959  EXPECT_TRUE(A.IsIdentity());
1960
1961  InitializeTestMatrix(&A);
1962  A.RotateAbout(Vector3dF(0.0, 0.0, 0.0), 35.0);
1963
1964  // Verify that A remains unchanged.
1965  EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, A);
1966  EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, A);
1967  EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, A);
1968  EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, A);
1969}
1970
1971TEST(XFormTest, verifySkewX) {
1972  Transform A;
1973  A.SkewX(45.0);
1974  EXPECT_ROW1_EQ(1.0f, 1.0f, 0.0f, 0.0f, A);
1975  EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1976  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1977  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1978
1979  // Verify that skewX() post-multiplies the existing matrix. Row 1, column 2,
1980  // would incorrectly have value "7" if the matrix is pre-multiplied instead
1981  // of post-multiplied.
1982  A.MakeIdentity();
1983  A.Scale3d(6.0, 7.0, 8.0);
1984  A.SkewX(45.0);
1985  EXPECT_ROW1_EQ(6.0f, 6.0f, 0.0f, 0.0f, A);
1986  EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 0.0f, A);
1987  EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
1988  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1989}
1990
1991TEST(XFormTest, verifySkewY) {
1992  Transform A;
1993  A.SkewY(45.0);
1994  EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1995  EXPECT_ROW2_EQ(1.0f, 1.0f, 0.0f, 0.0f, A);
1996  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1997  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1998
1999  // Verify that skewY() post-multiplies the existing matrix. Row 2, column 1 ,
2000  // would incorrectly have value "6" if the matrix is pre-multiplied instead
2001  // of post-multiplied.
2002  A.MakeIdentity();
2003  A.Scale3d(6.0, 7.0, 8.0);
2004  A.SkewY(45.0);
2005  EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 0.0f, A);
2006  EXPECT_ROW2_EQ(7.0f, 7.0f, 0.0f, 0.0f, A);
2007  EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
2008  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
2009}
2010
2011TEST(XFormTest, verifyPerspectiveDepth) {
2012  Transform A;
2013  A.ApplyPerspectiveDepth(1.0);
2014  EXPECT_ROW1_EQ(1.0f, 0.0f,  0.0f, 0.0f, A);
2015  EXPECT_ROW2_EQ(0.0f, 1.0f,  0.0f, 0.0f, A);
2016  EXPECT_ROW3_EQ(0.0f, 0.0f,  1.0f, 0.0f, A);
2017  EXPECT_ROW4_EQ(0.0f, 0.0f, -1.0f, 1.0f, A);
2018
2019  // Verify that PerspectiveDepth() post-multiplies the existing matrix.
2020  A.MakeIdentity();
2021  A.Translate3d(2.0, 3.0, 4.0);
2022  A.ApplyPerspectiveDepth(1.0);
2023  EXPECT_ROW1_EQ(1.0f, 0.0f, -2.0f, 2.0f, A);
2024  EXPECT_ROW2_EQ(0.0f, 1.0f, -3.0f, 3.0f, A);
2025  EXPECT_ROW3_EQ(0.0f, 0.0f, -3.0f, 4.0f, A);
2026  EXPECT_ROW4_EQ(0.0f, 0.0f, -1.0f, 1.0f, A);
2027}
2028
2029TEST(XFormTest, verifyHasPerspective) {
2030  Transform A;
2031  A.ApplyPerspectiveDepth(1.0);
2032  EXPECT_TRUE(A.HasPerspective());
2033
2034  A.MakeIdentity();
2035  A.ApplyPerspectiveDepth(0.0);
2036  EXPECT_FALSE(A.HasPerspective());
2037
2038  A.MakeIdentity();
2039  A.matrix().set(3, 0, -1.f);
2040  EXPECT_TRUE(A.HasPerspective());
2041
2042  A.MakeIdentity();
2043  A.matrix().set(3, 1, -1.f);
2044  EXPECT_TRUE(A.HasPerspective());
2045
2046  A.MakeIdentity();
2047  A.matrix().set(3, 2, -0.3f);
2048  EXPECT_TRUE(A.HasPerspective());
2049
2050  A.MakeIdentity();
2051  A.matrix().set(3, 3, 0.5f);
2052  EXPECT_TRUE(A.HasPerspective());
2053
2054  A.MakeIdentity();
2055  A.matrix().set(3, 3, 0.f);
2056  EXPECT_TRUE(A.HasPerspective());
2057}
2058
2059TEST(XFormTest, verifyIsInvertible) {
2060  Transform A;
2061
2062  // Translations, rotations, scales, skews and arbitrary combinations of them
2063  // are invertible.
2064  A.MakeIdentity();
2065  EXPECT_TRUE(A.IsInvertible());
2066
2067  A.MakeIdentity();
2068  A.Translate3d(2.0, 3.0, 4.0);
2069  EXPECT_TRUE(A.IsInvertible());
2070
2071  A.MakeIdentity();
2072  A.Scale3d(6.0, 7.0, 8.0);
2073  EXPECT_TRUE(A.IsInvertible());
2074
2075  A.MakeIdentity();
2076  A.RotateAboutXAxis(10.0);
2077  A.RotateAboutYAxis(20.0);
2078  A.RotateAboutZAxis(30.0);
2079  EXPECT_TRUE(A.IsInvertible());
2080
2081  A.MakeIdentity();
2082  A.SkewX(45.0);
2083  EXPECT_TRUE(A.IsInvertible());
2084
2085  // A perspective matrix (projection plane at z=0) is invertible. The
2086  // intuitive explanation is that perspective is eqivalent to a skew of the
2087  // w-axis; skews are invertible.
2088  A.MakeIdentity();
2089  A.ApplyPerspectiveDepth(1.0);
2090  EXPECT_TRUE(A.IsInvertible());
2091
2092  // A "pure" perspective matrix derived by similar triangles, with m44() set
2093  // to zero (i.e. camera positioned at the origin), is not invertible.
2094  A.MakeIdentity();
2095  A.ApplyPerspectiveDepth(1.0);
2096  A.matrix().set(3, 3, 0.f);
2097  EXPECT_FALSE(A.IsInvertible());
2098
2099  // Adding more to a non-invertible matrix will not make it invertible in the
2100  // general case.
2101  A.MakeIdentity();
2102  A.ApplyPerspectiveDepth(1.0);
2103  A.matrix().set(3, 3, 0.f);
2104  A.Scale3d(6.0, 7.0, 8.0);
2105  A.RotateAboutXAxis(10.0);
2106  A.RotateAboutYAxis(20.0);
2107  A.RotateAboutZAxis(30.0);
2108  A.Translate3d(6.0, 7.0, 8.0);
2109  EXPECT_FALSE(A.IsInvertible());
2110
2111  // A degenerate matrix of all zeros is not invertible.
2112  A.MakeIdentity();
2113  A.matrix().set(0, 0, 0.f);
2114  A.matrix().set(1, 1, 0.f);
2115  A.matrix().set(2, 2, 0.f);
2116  A.matrix().set(3, 3, 0.f);
2117  EXPECT_FALSE(A.IsInvertible());
2118}
2119
2120TEST(XFormTest, verifyIsIdentity) {
2121  Transform A;
2122
2123  InitializeTestMatrix(&A);
2124  EXPECT_FALSE(A.IsIdentity());
2125
2126  A.MakeIdentity();
2127  EXPECT_TRUE(A.IsIdentity());
2128
2129  // Modifying any one individual element should cause the matrix to no longer
2130  // be identity.
2131  A.MakeIdentity();
2132  A.matrix().set(0, 0, 2.f);
2133  EXPECT_FALSE(A.IsIdentity());
2134
2135  A.MakeIdentity();
2136  A.matrix().set(1, 0, 2.f);
2137  EXPECT_FALSE(A.IsIdentity());
2138
2139  A.MakeIdentity();
2140  A.matrix().set(2, 0, 2.f);
2141  EXPECT_FALSE(A.IsIdentity());
2142
2143  A.MakeIdentity();
2144  A.matrix().set(3, 0, 2.f);
2145  EXPECT_FALSE(A.IsIdentity());
2146
2147  A.MakeIdentity();
2148  A.matrix().set(0, 1, 2.f);
2149  EXPECT_FALSE(A.IsIdentity());
2150
2151  A.MakeIdentity();
2152  A.matrix().set(1, 1, 2.f);
2153  EXPECT_FALSE(A.IsIdentity());
2154
2155  A.MakeIdentity();
2156  A.matrix().set(2, 1, 2.f);
2157  EXPECT_FALSE(A.IsIdentity());
2158
2159  A.MakeIdentity();
2160  A.matrix().set(3, 1, 2.f);
2161  EXPECT_FALSE(A.IsIdentity());
2162
2163  A.MakeIdentity();
2164  A.matrix().set(0, 2, 2.f);
2165  EXPECT_FALSE(A.IsIdentity());
2166
2167  A.MakeIdentity();
2168  A.matrix().set(1, 2, 2.f);
2169  EXPECT_FALSE(A.IsIdentity());
2170
2171  A.MakeIdentity();
2172  A.matrix().set(2, 2, 2.f);
2173  EXPECT_FALSE(A.IsIdentity());
2174
2175  A.MakeIdentity();
2176  A.matrix().set(3, 2, 2.f);
2177  EXPECT_FALSE(A.IsIdentity());
2178
2179  A.MakeIdentity();
2180  A.matrix().set(0, 3, 2.f);
2181  EXPECT_FALSE(A.IsIdentity());
2182
2183  A.MakeIdentity();
2184  A.matrix().set(1, 3, 2.f);
2185  EXPECT_FALSE(A.IsIdentity());
2186
2187  A.MakeIdentity();
2188  A.matrix().set(2, 3, 2.f);
2189  EXPECT_FALSE(A.IsIdentity());
2190
2191  A.MakeIdentity();
2192  A.matrix().set(3, 3, 2.f);
2193  EXPECT_FALSE(A.IsIdentity());
2194}
2195
2196TEST(XFormTest, verifyIsIdentityOrTranslation) {
2197  Transform A;
2198
2199  InitializeTestMatrix(&A);
2200  EXPECT_FALSE(A.IsIdentityOrTranslation());
2201
2202  A.MakeIdentity();
2203  EXPECT_TRUE(A.IsIdentityOrTranslation());
2204
2205  // Modifying any non-translation components should cause
2206  // IsIdentityOrTranslation() to return false. NOTE: (0, 3), (1, 3), and
2207  // (2, 3) are the translation components, so modifying them should still
2208  // return true.
2209  A.MakeIdentity();
2210  A.matrix().set(0, 0, 2.f);
2211  EXPECT_FALSE(A.IsIdentityOrTranslation());
2212
2213  A.MakeIdentity();
2214  A.matrix().set(1, 0, 2.f);
2215  EXPECT_FALSE(A.IsIdentityOrTranslation());
2216
2217  A.MakeIdentity();
2218  A.matrix().set(2, 0, 2.f);
2219  EXPECT_FALSE(A.IsIdentityOrTranslation());
2220
2221  A.MakeIdentity();
2222  A.matrix().set(3, 0, 2.f);
2223  EXPECT_FALSE(A.IsIdentityOrTranslation());
2224
2225  A.MakeIdentity();
2226  A.matrix().set(0, 1, 2.f);
2227  EXPECT_FALSE(A.IsIdentityOrTranslation());
2228
2229  A.MakeIdentity();
2230  A.matrix().set(1, 1, 2.f);
2231  EXPECT_FALSE(A.IsIdentityOrTranslation());
2232
2233  A.MakeIdentity();
2234  A.matrix().set(2, 1, 2.f);
2235  EXPECT_FALSE(A.IsIdentityOrTranslation());
2236
2237  A.MakeIdentity();
2238  A.matrix().set(3, 1, 2.f);
2239  EXPECT_FALSE(A.IsIdentityOrTranslation());
2240
2241  A.MakeIdentity();
2242  A.matrix().set(0, 2, 2.f);
2243  EXPECT_FALSE(A.IsIdentityOrTranslation());
2244
2245  A.MakeIdentity();
2246  A.matrix().set(1, 2, 2.f);
2247  EXPECT_FALSE(A.IsIdentityOrTranslation());
2248
2249  A.MakeIdentity();
2250  A.matrix().set(2, 2, 2.f);
2251  EXPECT_FALSE(A.IsIdentityOrTranslation());
2252
2253  A.MakeIdentity();
2254  A.matrix().set(3, 2, 2.f);
2255  EXPECT_FALSE(A.IsIdentityOrTranslation());
2256
2257  // Note carefully - expecting true here.
2258  A.MakeIdentity();
2259  A.matrix().set(0, 3, 2.f);
2260  EXPECT_TRUE(A.IsIdentityOrTranslation());
2261
2262  // Note carefully - expecting true here.
2263  A.MakeIdentity();
2264  A.matrix().set(1, 3, 2.f);
2265  EXPECT_TRUE(A.IsIdentityOrTranslation());
2266
2267  // Note carefully - expecting true here.
2268  A.MakeIdentity();
2269  A.matrix().set(2, 3, 2.f);
2270  EXPECT_TRUE(A.IsIdentityOrTranslation());
2271
2272  A.MakeIdentity();
2273  A.matrix().set(3, 3, 2.f);
2274  EXPECT_FALSE(A.IsIdentityOrTranslation());
2275}
2276
2277TEST(XFormTest, verifyIsApproximatelyIdentityOrTranslation) {
2278  Transform A;
2279  SkMatrix44& matrix = A.matrix();
2280
2281  // Exact pure translation.
2282  A.MakeIdentity();
2283
2284  // Set translate values to values other than 0 or 1.
2285  matrix.set(0, 3, 3.4f);
2286  matrix.set(1, 3, 4.4f);
2287  matrix.set(2, 3, 5.6f);
2288
2289  EXPECT_TRUE(A.IsApproximatelyIdentityOrTranslation(0));
2290  EXPECT_TRUE(A.IsApproximatelyIdentityOrTranslation(kApproxZero));
2291
2292  // Approximately pure translation.
2293  InitializeApproxIdentityMatrix(&A);
2294
2295  // Some values must be exact.
2296  matrix.set(3, 0, 0);
2297  matrix.set(3, 1, 0);
2298  matrix.set(3, 2, 0);
2299  matrix.set(3, 3, 1);
2300
2301  // Set translate values to values other than 0 or 1.
2302  matrix.set(0, 3, 3.4f);
2303  matrix.set(1, 3, 4.4f);
2304  matrix.set(2, 3, 5.6f);
2305
2306  EXPECT_FALSE(A.IsApproximatelyIdentityOrTranslation(0));
2307  EXPECT_TRUE(A.IsApproximatelyIdentityOrTranslation(kApproxZero));
2308
2309  // Not approximately pure translation.
2310  InitializeApproxIdentityMatrix(&A);
2311
2312  // Some values must be exact.
2313  matrix.set(3, 0, 0);
2314  matrix.set(3, 1, 0);
2315  matrix.set(3, 2, 0);
2316  matrix.set(3, 3, 1);
2317
2318  // Set some values (not translate values) to values other than 0 or 1.
2319  matrix.set(0, 1, 3.4f);
2320  matrix.set(3, 2, 4.4f);
2321  matrix.set(2, 0, 5.6f);
2322
2323  EXPECT_FALSE(A.IsApproximatelyIdentityOrTranslation(0));
2324  EXPECT_FALSE(A.IsApproximatelyIdentityOrTranslation(kApproxZero));
2325}
2326
2327TEST(XFormTest, verifyIsScaleOrTranslation) {
2328  Transform A;
2329
2330  InitializeTestMatrix(&A);
2331  EXPECT_FALSE(A.IsScaleOrTranslation());
2332
2333  A.MakeIdentity();
2334  EXPECT_TRUE(A.IsScaleOrTranslation());
2335
2336  // Modifying any non-scale or non-translation components should cause
2337  // IsScaleOrTranslation() to return false. (0, 0), (1, 1), (2, 2), (0, 3),
2338  // (1, 3), and (2, 3) are the scale and translation components, so
2339  // modifying them should still return true.
2340
2341  // Note carefully - expecting true here.
2342  A.MakeIdentity();
2343  A.matrix().set(0, 0, 2.f);
2344  EXPECT_TRUE(A.IsScaleOrTranslation());
2345
2346  A.MakeIdentity();
2347  A.matrix().set(1, 0, 2.f);
2348  EXPECT_FALSE(A.IsScaleOrTranslation());
2349
2350  A.MakeIdentity();
2351  A.matrix().set(2, 0, 2.f);
2352  EXPECT_FALSE(A.IsScaleOrTranslation());
2353
2354  A.MakeIdentity();
2355  A.matrix().set(3, 0, 2.f);
2356  EXPECT_FALSE(A.IsScaleOrTranslation());
2357
2358  A.MakeIdentity();
2359  A.matrix().set(0, 1, 2.f);
2360  EXPECT_FALSE(A.IsScaleOrTranslation());
2361
2362  // Note carefully - expecting true here.
2363  A.MakeIdentity();
2364  A.matrix().set(1, 1, 2.f);
2365  EXPECT_TRUE(A.IsScaleOrTranslation());
2366
2367  A.MakeIdentity();
2368  A.matrix().set(2, 1, 2.f);
2369  EXPECT_FALSE(A.IsScaleOrTranslation());
2370
2371  A.MakeIdentity();
2372  A.matrix().set(3, 1, 2.f);
2373  EXPECT_FALSE(A.IsScaleOrTranslation());
2374
2375  A.MakeIdentity();
2376  A.matrix().set(0, 2, 2.f);
2377  EXPECT_FALSE(A.IsScaleOrTranslation());
2378
2379  A.MakeIdentity();
2380  A.matrix().set(1, 2, 2.f);
2381  EXPECT_FALSE(A.IsScaleOrTranslation());
2382
2383  // Note carefully - expecting true here.
2384  A.MakeIdentity();
2385  A.matrix().set(2, 2, 2.f);
2386  EXPECT_TRUE(A.IsScaleOrTranslation());
2387
2388  A.MakeIdentity();
2389  A.matrix().set(3, 2, 2.f);
2390  EXPECT_FALSE(A.IsScaleOrTranslation());
2391
2392  // Note carefully - expecting true here.
2393  A.MakeIdentity();
2394  A.matrix().set(0, 3, 2.f);
2395  EXPECT_TRUE(A.IsScaleOrTranslation());
2396
2397  // Note carefully - expecting true here.
2398  A.MakeIdentity();
2399  A.matrix().set(1, 3, 2.f);
2400  EXPECT_TRUE(A.IsScaleOrTranslation());
2401
2402  // Note carefully - expecting true here.
2403  A.MakeIdentity();
2404  A.matrix().set(2, 3, 2.f);
2405  EXPECT_TRUE(A.IsScaleOrTranslation());
2406
2407  A.MakeIdentity();
2408  A.matrix().set(3, 3, 2.f);
2409  EXPECT_FALSE(A.IsScaleOrTranslation());
2410}
2411
2412TEST(XFormTest, verifyFlattenTo2d) {
2413  Transform A;
2414  InitializeTestMatrix(&A);
2415
2416  A.FlattenTo2d();
2417  EXPECT_ROW1_EQ(10.0f, 14.0f, 0.0f, 22.0f, A);
2418  EXPECT_ROW2_EQ(11.0f, 15.0f, 0.0f, 23.0f, A);
2419  EXPECT_ROW3_EQ(0.0f,  0.0f,  1.0f, 0.0f,  A);
2420  EXPECT_ROW4_EQ(13.0f, 17.0f, 0.0f, 25.0f, A);
2421}
2422
2423// Another implementation of Preserves2dAxisAlignment that isn't as fast,
2424// good for testing the faster implementation.
2425static bool EmpiricallyPreserves2dAxisAlignment(const Transform& transform) {
2426  Point3F p1(5.0f, 5.0f, 0.0f);
2427  Point3F p2(10.0f, 5.0f, 0.0f);
2428  Point3F p3(10.0f, 20.0f, 0.0f);
2429  Point3F p4(5.0f, 20.0f, 0.0f);
2430
2431  QuadF test_quad(PointF(p1.x(), p1.y()),
2432                 PointF(p2.x(), p2.y()),
2433                 PointF(p3.x(), p3.y()),
2434                 PointF(p4.x(), p4.y()));
2435  EXPECT_TRUE(test_quad.IsRectilinear());
2436
2437  transform.TransformPoint(&p1);
2438  transform.TransformPoint(&p2);
2439  transform.TransformPoint(&p3);
2440  transform.TransformPoint(&p4);
2441
2442  QuadF transformedQuad(PointF(p1.x(), p1.y()),
2443                        PointF(p2.x(), p2.y()),
2444                        PointF(p3.x(), p3.y()),
2445                        PointF(p4.x(), p4.y()));
2446  return transformedQuad.IsRectilinear();
2447}
2448
2449TEST(XFormTest, Preserves2dAxisAlignment) {
2450  static const struct TestCase {
2451    SkMScalar a; // row 1, column 1
2452    SkMScalar b; // row 1, column 2
2453    SkMScalar c; // row 2, column 1
2454    SkMScalar d; // row 2, column 2
2455    bool expected;
2456  } test_cases[] = {
2457    { 3.f, 0.f,
2458      0.f, 4.f, true }, // basic case
2459    { 0.f, 4.f,
2460      3.f, 0.f, true }, // rotate by 90
2461    { 0.f, 0.f,
2462      0.f, 4.f, true }, // degenerate x
2463    { 3.f, 0.f,
2464      0.f, 0.f, true }, // degenerate y
2465    { 0.f, 0.f,
2466      3.f, 0.f, true }, // degenerate x + rotate by 90
2467    { 0.f, 4.f,
2468      0.f, 0.f, true }, // degenerate y + rotate by 90
2469    { 3.f, 4.f,
2470      0.f, 0.f, false },
2471    { 0.f, 0.f,
2472      3.f, 4.f, false },
2473    { 0.f, 3.f,
2474      0.f, 4.f, false },
2475    { 3.f, 0.f,
2476      4.f, 0.f, false },
2477    { 3.f, 4.f,
2478      5.f, 0.f, false },
2479    { 3.f, 4.f,
2480      0.f, 5.f, false },
2481    { 3.f, 0.f,
2482      4.f, 5.f, false },
2483    { 0.f, 3.f,
2484      4.f, 5.f, false },
2485    { 2.f, 3.f,
2486      4.f, 5.f, false },
2487  };
2488
2489  Transform transform;
2490  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
2491    const TestCase& value = test_cases[i];
2492    transform.MakeIdentity();
2493    transform.matrix().set(0, 0, value.a);
2494    transform.matrix().set(0, 1, value.b);
2495    transform.matrix().set(1, 0, value.c);
2496    transform.matrix().set(1, 1, value.d);
2497
2498    if (value.expected) {
2499      EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2500      EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2501    } else {
2502      EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform));
2503      EXPECT_FALSE(transform.Preserves2dAxisAlignment());
2504    }
2505  }
2506
2507  // Try the same test cases again, but this time make sure that other matrix
2508  // elements (except perspective) have entries, to test that they are ignored.
2509  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
2510    const TestCase& value = test_cases[i];
2511    transform.MakeIdentity();
2512    transform.matrix().set(0, 0, value.a);
2513    transform.matrix().set(0, 1, value.b);
2514    transform.matrix().set(1, 0, value.c);
2515    transform.matrix().set(1, 1, value.d);
2516
2517    transform.matrix().set(0, 2, 1.f);
2518    transform.matrix().set(0, 3, 2.f);
2519    transform.matrix().set(1, 2, 3.f);
2520    transform.matrix().set(1, 3, 4.f);
2521    transform.matrix().set(2, 0, 5.f);
2522    transform.matrix().set(2, 1, 6.f);
2523    transform.matrix().set(2, 2, 7.f);
2524    transform.matrix().set(2, 3, 8.f);
2525
2526    if (value.expected) {
2527      EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2528      EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2529    } else {
2530      EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform));
2531      EXPECT_FALSE(transform.Preserves2dAxisAlignment());
2532    }
2533  }
2534
2535  // Try the same test cases again, but this time add perspective which is
2536  // always assumed to not-preserve axis alignment.
2537  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
2538    const TestCase& value = test_cases[i];
2539    transform.MakeIdentity();
2540    transform.matrix().set(0, 0, value.a);
2541    transform.matrix().set(0, 1, value.b);
2542    transform.matrix().set(1, 0, value.c);
2543    transform.matrix().set(1, 1, value.d);
2544
2545    transform.matrix().set(0, 2, 1.f);
2546    transform.matrix().set(0, 3, 2.f);
2547    transform.matrix().set(1, 2, 3.f);
2548    transform.matrix().set(1, 3, 4.f);
2549    transform.matrix().set(2, 0, 5.f);
2550    transform.matrix().set(2, 1, 6.f);
2551    transform.matrix().set(2, 2, 7.f);
2552    transform.matrix().set(2, 3, 8.f);
2553    transform.matrix().set(3, 0, 9.f);
2554    transform.matrix().set(3, 1, 10.f);
2555    transform.matrix().set(3, 2, 11.f);
2556    transform.matrix().set(3, 3, 12.f);
2557
2558    EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform));
2559    EXPECT_FALSE(transform.Preserves2dAxisAlignment());
2560  }
2561
2562  // Try a few more practical situations to check precision
2563  transform.MakeIdentity();
2564  transform.RotateAboutZAxis(90.0);
2565  EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2566  EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2567
2568  transform.MakeIdentity();
2569  transform.RotateAboutZAxis(180.0);
2570  EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2571  EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2572
2573  transform.MakeIdentity();
2574  transform.RotateAboutZAxis(270.0);
2575  EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2576  EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2577
2578  transform.MakeIdentity();
2579  transform.RotateAboutYAxis(90.0);
2580  EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2581  EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2582
2583  transform.MakeIdentity();
2584  transform.RotateAboutXAxis(90.0);
2585  EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2586  EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2587
2588  transform.MakeIdentity();
2589  transform.RotateAboutZAxis(90.0);
2590  transform.RotateAboutYAxis(90.0);
2591  EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2592  EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2593
2594  transform.MakeIdentity();
2595  transform.RotateAboutZAxis(90.0);
2596  transform.RotateAboutXAxis(90.0);
2597  EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2598  EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2599
2600  transform.MakeIdentity();
2601  transform.RotateAboutYAxis(90.0);
2602  transform.RotateAboutZAxis(90.0);
2603  EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2604  EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2605
2606  transform.MakeIdentity();
2607  transform.RotateAboutZAxis(45.0);
2608  EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform));
2609  EXPECT_FALSE(transform.Preserves2dAxisAlignment());
2610
2611  // 3-d case; In 2d after an orthographic projection, this case does
2612  // preserve 2d axis alignment. But in 3d, it does not preserve axis
2613  // alignment.
2614  transform.MakeIdentity();
2615  transform.RotateAboutYAxis(45.0);
2616  EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2617  EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2618
2619  transform.MakeIdentity();
2620  transform.RotateAboutXAxis(45.0);
2621  EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2622  EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2623
2624  // Perspective cases.
2625  transform.MakeIdentity();
2626  transform.ApplyPerspectiveDepth(10.0);
2627  transform.RotateAboutYAxis(45.0);
2628  EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform));
2629  EXPECT_FALSE(transform.Preserves2dAxisAlignment());
2630
2631  transform.MakeIdentity();
2632  transform.ApplyPerspectiveDepth(10.0);
2633  transform.RotateAboutZAxis(90.0);
2634  EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2635  EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2636}
2637
2638TEST(XFormTest, To2dTranslation) {
2639  Vector2dF translation(3.f, 7.f);
2640  Transform transform;
2641  transform.Translate(translation.x(), translation.y() + 1);
2642  EXPECT_NE(translation.ToString(), transform.To2dTranslation().ToString());
2643  transform.MakeIdentity();
2644  transform.Translate(translation.x(), translation.y());
2645  EXPECT_EQ(translation.ToString(), transform.To2dTranslation().ToString());
2646}
2647
2648TEST(XFormTest, TransformRect) {
2649  Transform translation;
2650  translation.Translate(3.f, 7.f);
2651  RectF rect(1.f, 2.f, 3.f, 4.f);
2652  RectF expected(4.f, 9.f, 3.f, 4.f);
2653  translation.TransformRect(&rect);
2654  EXPECT_EQ(expected.ToString(), rect.ToString());
2655}
2656
2657TEST(XFormTest, TransformRectReverse) {
2658  Transform translation;
2659  translation.Translate(3.f, 7.f);
2660  RectF rect(1.f, 2.f, 3.f, 4.f);
2661  RectF expected(-2.f, -5.f, 3.f, 4.f);
2662  EXPECT_TRUE(translation.TransformRectReverse(&rect));
2663  EXPECT_EQ(expected.ToString(), rect.ToString());
2664
2665  Transform singular;
2666  singular.Scale3d(0.f, 0.f, 0.f);
2667  EXPECT_FALSE(singular.TransformRectReverse(&rect));
2668}
2669
2670TEST(XFormTest, TransformBox) {
2671  Transform translation;
2672  translation.Translate3d(3.f, 7.f, 6.f);
2673  BoxF box(1.f, 2.f, 3.f, 4.f, 5.f, 6.f);
2674  BoxF expected(4.f, 9.f, 9.f, 4.f, 5.f, 6.f);
2675  translation.TransformBox(&box);
2676  EXPECT_EQ(expected.ToString(), box.ToString());
2677}
2678
2679TEST(XFormTest, TransformBoxReverse) {
2680  Transform translation;
2681  translation.Translate3d(3.f, 7.f, 6.f);
2682  BoxF box(1.f, 2.f, 3.f, 4.f, 5.f, 6.f);
2683  BoxF expected(-2.f, -5.f, -3.f, 4.f, 5.f, 6.f);
2684  EXPECT_TRUE(translation.TransformBoxReverse(&box));
2685  EXPECT_EQ(expected.ToString(), box.ToString());
2686
2687  Transform singular;
2688  singular.Scale3d(0.f, 0.f, 0.f);
2689  EXPECT_FALSE(singular.TransformBoxReverse(&box));
2690}
2691
2692}  // namespace
2693
2694}  // namespace gfx
2695