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
738TEST(XFormTest, BlendRotateFollowsShortestPath) {
739  // Verify that we interpolate along the shortest path regardless of whether
740  // this path crosses the 180-degree point.
741  Vector3dF axes[] = {
742    Vector3dF(1, 0, 0),
743    Vector3dF(0, 1, 0),
744    Vector3dF(0, 0, 1),
745    Vector3dF(1, 1, 1)
746  };
747  for (size_t index = 0; index < ARRAYSIZE_UNSAFE(axes); ++index) {
748    for (int i = -5; i < 15; ++i) {
749      Transform from1;
750      from1.RotateAbout(axes[index], 130.0);
751      Transform to1;
752      to1.RotateAbout(axes[index], 175.0);
753
754      Transform from2;
755      from2.RotateAbout(axes[index], 140.0);
756      Transform to2;
757      to2.RotateAbout(axes[index], 185.0);
758
759      double t = i / 9.0;
760      EXPECT_TRUE(to1.Blend(from1, t));
761      EXPECT_TRUE(to2.Blend(from2, t));
762
763      Transform expected1;
764      expected1.RotateAbout(axes[index], 130.0 + 45.0 * t);
765
766      Transform expected2;
767      expected2.RotateAbout(axes[index], 140.0 + 45.0 * t);
768
769      EXPECT_TRUE(MatricesAreNearlyEqual(expected1, to1));
770      EXPECT_TRUE(MatricesAreNearlyEqual(expected2, to2));
771    }
772  }
773}
774
775TEST(XFormTest, CanBlend180DegreeRotation) {
776  Vector3dF axes[] = {
777    Vector3dF(1, 0, 0),
778    Vector3dF(0, 1, 0),
779    Vector3dF(0, 0, 1),
780    Vector3dF(1, 1, 1)
781  };
782  Transform from;
783  for (size_t index = 0; index < ARRAYSIZE_UNSAFE(axes); ++index) {
784    for (int i = -5; i < 15; ++i) {
785      Transform to;
786      to.RotateAbout(axes[index], 180.0);
787      double t = i / 9.0;
788      EXPECT_TRUE(to.Blend(from, t));
789
790      // A 180 degree rotation is exactly opposite on the sphere, therefore
791      // either great circle arc to it is equivalent (and numerical precision
792      // will determine which is closer).  Test both directions.
793      Transform expected1;
794      expected1.RotateAbout(axes[index], 180.0 * t);
795      Transform expected2;
796      expected2.RotateAbout(axes[index], -180.0 * t);
797
798      EXPECT_TRUE(MatricesAreNearlyEqual(expected1, to) ||
799                  MatricesAreNearlyEqual(expected2, to))
800          << "axis: " << index << ", i: " << i;
801    }
802  }
803}
804
805TEST(XFormTest, BlendScale) {
806  Transform from;
807  for (int i = -5; i < 15; ++i) {
808    Transform to;
809    to.Scale3d(5, 4, 3);
810    double t = i / 9.0;
811    EXPECT_TRUE(to.Blend(from, t));
812    EXPECT_FLOAT_EQ(t * 4 + 1, to.matrix().get(0, 0)) << "i: " << i;
813    EXPECT_FLOAT_EQ(t * 3 + 1, to.matrix().get(1, 1)) << "i: " << i;
814    EXPECT_FLOAT_EQ(t * 2 + 1, to.matrix().get(2, 2)) << "i: " << i;
815  }
816}
817
818TEST(XFormTest, BlendSkew) {
819  Transform from;
820  for (int i = 0; i < 2; ++i) {
821    Transform to;
822    to.SkewX(10);
823    to.SkewY(5);
824    double t = i;
825    Transform expected;
826    expected.SkewX(t * 10);
827    expected.SkewY(t * 5);
828    EXPECT_TRUE(to.Blend(from, t));
829    EXPECT_TRUE(MatricesAreNearlyEqual(expected, to));
830  }
831}
832
833TEST(XFormTest, ExtrapolateSkew) {
834  Transform from;
835  for (int i = -1; i < 2; ++i) {
836    Transform to;
837    to.SkewX(20);
838    double t = i;
839    Transform expected;
840    expected.SkewX(t * 20);
841    EXPECT_TRUE(to.Blend(from, t));
842    EXPECT_TRUE(MatricesAreNearlyEqual(expected, to));
843  }
844}
845
846TEST(XFormTest, BlendPerspective) {
847  Transform from;
848  from.ApplyPerspectiveDepth(200);
849  for (int i = -1; i < 3; ++i) {
850    Transform to;
851    to.ApplyPerspectiveDepth(800);
852    double t = i;
853    double depth = 1.0 / ((1.0 / 200) * (1.0 - t) + (1.0 / 800) * t);
854    Transform expected;
855    expected.ApplyPerspectiveDepth(depth);
856    EXPECT_TRUE(to.Blend(from, t));
857    EXPECT_TRUE(MatricesAreNearlyEqual(expected, to));
858  }
859}
860
861TEST(XFormTest, BlendIdentity) {
862  Transform from;
863  Transform to;
864  EXPECT_TRUE(to.Blend(from, 0.5));
865  EXPECT_EQ(to, from);
866}
867
868TEST(XFormTest, CannotBlendSingularMatrix) {
869  Transform from;
870  Transform to;
871  to.matrix().set(1, 1, SkDoubleToMScalar(0));
872  EXPECT_FALSE(to.Blend(from, 0.5));
873}
874
875TEST(XFormTest, VerifyBlendForTranslation) {
876  Transform from;
877  from.Translate3d(100.0, 200.0, 100.0);
878
879  Transform to;
880
881  to.Translate3d(200.0, 100.0, 300.0);
882  to.Blend(from, 0.0);
883  EXPECT_EQ(from, to);
884
885  to = Transform();
886  to.Translate3d(200.0, 100.0, 300.0);
887  to.Blend(from, 0.25);
888  EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 125.0f, to);
889  EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 175.0f, to);
890  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 150.0f, to);
891  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f,  1.0f,  to);
892
893  to = Transform();
894  to.Translate3d(200.0, 100.0, 300.0);
895  to.Blend(from, 0.5);
896  EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 150.0f, to);
897  EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 150.0f, to);
898  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 200.0f, to);
899  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f,  1.0f,  to);
900
901  to = Transform();
902  to.Translate3d(200.0, 100.0, 300.0);
903  to.Blend(from, 1.0);
904  EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 200.0f, to);
905  EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 100.0f, to);
906  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 300.0f, to);
907  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f,  1.0f,  to);
908}
909
910TEST(XFormTest, VerifyBlendForScale) {
911  Transform from;
912  from.Scale3d(100.0, 200.0, 100.0);
913
914  Transform to;
915
916  to.Scale3d(200.0, 100.0, 300.0);
917  to.Blend(from, 0.0);
918  EXPECT_EQ(from, to);
919
920  to = Transform();
921  to.Scale3d(200.0, 100.0, 300.0);
922  to.Blend(from, 0.25);
923  EXPECT_ROW1_EQ(125.0f, 0.0f,  0.0f,  0.0f, to);
924  EXPECT_ROW2_EQ(0.0f,  175.0f, 0.0f,  0.0f, to);
925  EXPECT_ROW3_EQ(0.0f,   0.0f, 150.0f, 0.0f, to);
926  EXPECT_ROW4_EQ(0.0f,   0.0f,  0.0f,  1.0f, to);
927
928  to = Transform();
929  to.Scale3d(200.0, 100.0, 300.0);
930  to.Blend(from, 0.5);
931  EXPECT_ROW1_EQ(150.0f, 0.0f,  0.0f,  0.0f, to);
932  EXPECT_ROW2_EQ(0.0f,  150.0f, 0.0f,  0.0f, to);
933  EXPECT_ROW3_EQ(0.0f,   0.0f, 200.0f, 0.0f, to);
934  EXPECT_ROW4_EQ(0.0f,   0.0f,  0.0f,  1.0f, to);
935
936  to = Transform();
937  to.Scale3d(200.0, 100.0, 300.0);
938  to.Blend(from, 1.0);
939  EXPECT_ROW1_EQ(200.0f, 0.0f,  0.0f,  0.0f, to);
940  EXPECT_ROW2_EQ(0.0f,  100.0f, 0.0f,  0.0f, to);
941  EXPECT_ROW3_EQ(0.0f,   0.0f, 300.0f, 0.0f, to);
942  EXPECT_ROW4_EQ(0.0f,   0.0f,  0.0f,  1.0f, to);
943}
944
945TEST(XFormTest, VerifyBlendForSkewX) {
946  Transform from;
947  from.SkewX(0.0);
948
949  Transform to;
950
951  to.SkewX(45.0);
952  to.Blend(from, 0.0);
953  EXPECT_EQ(from, to);
954
955  to = Transform();
956  to.SkewX(45.0);
957  to.Blend(from, 0.5);
958  EXPECT_ROW1_EQ(1.0f, 0.5f, 0.0f, 0.0f, to);
959  EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, to);
960  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
961  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
962
963  to = Transform();
964  to.SkewX(45.0);
965  to.Blend(from, 0.25);
966  EXPECT_ROW1_EQ(1.0f, 0.25f, 0.0f, 0.0f, to);
967  EXPECT_ROW2_EQ(0.0f, 1.0f,  0.0f, 0.0f, to);
968  EXPECT_ROW3_EQ(0.0f, 0.0f,  1.0f, 0.0f, to);
969  EXPECT_ROW4_EQ(0.0f, 0.0f,  0.0f, 1.0f, to);
970
971  to = Transform();
972  to.SkewX(45.0);
973  to.Blend(from, 1.0);
974  EXPECT_ROW1_EQ(1.0f, 1.0f, 0.0f, 0.0f, to);
975  EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, to);
976  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
977  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
978}
979
980TEST(XFormTest, VerifyBlendForSkewY) {
981  // NOTE CAREFULLY: Decomposition of skew and rotation terms of the matrix
982  // is inherently underconstrained, and so it does not always compute the
983  // originally intended skew parameters. The current implementation uses QR
984  // decomposition, which decomposes the shear into a rotation + non-uniform
985  // scale.
986  //
987  // It is unlikely that the decomposition implementation will need to change
988  // very often, so to get any test coverage, the compromise is to verify the
989  // exact matrix that the.Blend() operation produces.
990  //
991  // This problem also potentially exists for skewX, but the current QR
992  // decomposition implementation just happens to decompose those test
993  // matrices intuitively.
994  //
995  // Unfortunately, this case suffers from uncomfortably large precision
996  // error.
997
998  Transform from;
999  from.SkewY(0.0);
1000
1001  Transform to;
1002
1003  to.SkewY(45.0);
1004  to.Blend(from, 0.0);
1005  EXPECT_EQ(from, to);
1006
1007  to = Transform();
1008  to.SkewY(45.0);
1009  to.Blend(from, 0.25);
1010  EXPECT_ROW1_NEAR(1.0823489449280947471976333,
1011                   0.0464370719145053845178239,
1012                   0.0,
1013                   0.0,
1014                   to,
1015                   LOOSE_ERROR_THRESHOLD);
1016  EXPECT_ROW2_NEAR(0.2152925909665224513123150,
1017                   0.9541702441750861130032035,
1018                   0.0,
1019                   0.0,
1020                   to,
1021                   LOOSE_ERROR_THRESHOLD);
1022  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
1023  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1024
1025  to = Transform();
1026  to.SkewY(45.0);
1027  to.Blend(from, 0.5);
1028  EXPECT_ROW1_NEAR(1.1152212925809066312865525,
1029                   0.0676495144007326631996335,
1030                   0.0,
1031                   0.0,
1032                   to,
1033                   LOOSE_ERROR_THRESHOLD);
1034  EXPECT_ROW2_NEAR(0.4619397844342648662419037,
1035                   0.9519009045724774464858342,
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, 1.0);
1046  EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, LOOSE_ERROR_THRESHOLD);
1047  EXPECT_ROW2_NEAR(1.0, 1.0, 0.0, 0.0, to, LOOSE_ERROR_THRESHOLD);
1048  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
1049  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1050}
1051
1052TEST(XFormTest, VerifyBlendForRotationAboutX) {
1053  // Even though.Blending uses quaternions, axis-aligned rotations should.
1054  // Blend the same with quaternions or Euler angles. So we can test
1055  // rotation.Blending by comparing against manually specified matrices from
1056  // Euler angles.
1057
1058  Transform from;
1059  from.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 0.0);
1060
1061  Transform to;
1062
1063  to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1064  to.Blend(from, 0.0);
1065  EXPECT_EQ(from, to);
1066
1067  double expectedRotationAngle = 22.5 * M_PI / 180.0;
1068  to = Transform();
1069  to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1070  to.Blend(from, 0.25);
1071  EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1072  EXPECT_ROW2_NEAR(0.0,
1073                   std::cos(expectedRotationAngle),
1074                   -std::sin(expectedRotationAngle),
1075                   0.0,
1076                   to,
1077                   ERROR_THRESHOLD);
1078  EXPECT_ROW3_NEAR(0.0,
1079                   std::sin(expectedRotationAngle),
1080                   std::cos(expectedRotationAngle),
1081                   0.0,
1082                   to,
1083                   ERROR_THRESHOLD);
1084  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1085
1086  expectedRotationAngle = 45.0 * M_PI / 180.0;
1087  to = Transform();
1088  to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1089  to.Blend(from, 0.5);
1090  EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1091  EXPECT_ROW2_NEAR(0.0,
1092                   std::cos(expectedRotationAngle),
1093                   -std::sin(expectedRotationAngle),
1094                   0.0,
1095                   to,
1096                   ERROR_THRESHOLD);
1097  EXPECT_ROW3_NEAR(0.0,
1098                   std::sin(expectedRotationAngle),
1099                   std::cos(expectedRotationAngle),
1100                   0.0,
1101                   to,
1102                   ERROR_THRESHOLD);
1103  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1104
1105  to = Transform();
1106  to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1107  to.Blend(from, 1.0);
1108  EXPECT_ROW1_NEAR(1.0, 0.0,  0.0, 0.0, to, ERROR_THRESHOLD);
1109  EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, to, ERROR_THRESHOLD);
1110  EXPECT_ROW3_NEAR(0.0, 1.0,  0.0, 0.0, to, ERROR_THRESHOLD);
1111  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1112}
1113
1114TEST(XFormTest, VerifyBlendForRotationAboutY) {
1115  Transform from;
1116  from.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 0.0);
1117
1118  Transform to;
1119
1120  to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1121  to.Blend(from, 0.0);
1122  EXPECT_EQ(from, to);
1123
1124  double expectedRotationAngle = 22.5 * M_PI / 180.0;
1125  to = Transform();
1126  to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1127  to.Blend(from, 0.25);
1128  EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle),
1129                   0.0,
1130                   std::sin(expectedRotationAngle),
1131                   0.0,
1132                   to,
1133                   ERROR_THRESHOLD);
1134  EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1135  EXPECT_ROW3_NEAR(-std::sin(expectedRotationAngle),
1136                   0.0,
1137                   std::cos(expectedRotationAngle),
1138                   0.0,
1139                   to,
1140                   ERROR_THRESHOLD);
1141  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1142
1143  expectedRotationAngle = 45.0 * M_PI / 180.0;
1144  to = Transform();
1145  to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1146  to.Blend(from, 0.5);
1147  EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle),
1148                   0.0,
1149                   std::sin(expectedRotationAngle),
1150                   0.0,
1151                   to,
1152                   ERROR_THRESHOLD);
1153  EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1154  EXPECT_ROW3_NEAR(-std::sin(expectedRotationAngle),
1155                   0.0,
1156                   std::cos(expectedRotationAngle),
1157                   0.0,
1158                   to,
1159                   ERROR_THRESHOLD);
1160  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1161
1162  to = Transform();
1163  to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1164  to.Blend(from, 1.0);
1165  EXPECT_ROW1_NEAR(0.0,  0.0, 1.0, 0.0, to, ERROR_THRESHOLD);
1166  EXPECT_ROW2_NEAR(0.0,  1.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1167  EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1168  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1169}
1170
1171TEST(XFormTest, VerifyBlendForRotationAboutZ) {
1172  Transform from;
1173  from.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 0.0);
1174
1175  Transform to;
1176
1177  to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1178  to.Blend(from, 0.0);
1179  EXPECT_EQ(from, to);
1180
1181  double expectedRotationAngle = 22.5 * M_PI / 180.0;
1182  to = Transform();
1183  to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1184  to.Blend(from, 0.25);
1185  EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle),
1186                   -std::sin(expectedRotationAngle),
1187                   0.0,
1188                   0.0,
1189                   to,
1190                   ERROR_THRESHOLD);
1191  EXPECT_ROW2_NEAR(std::sin(expectedRotationAngle),
1192                   std::cos(expectedRotationAngle),
1193                   0.0,
1194                   0.0,
1195                   to,
1196                   ERROR_THRESHOLD);
1197  EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to, ERROR_THRESHOLD);
1198  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1199
1200  expectedRotationAngle = 45.0 * M_PI / 180.0;
1201  to = Transform();
1202  to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1203  to.Blend(from, 0.5);
1204  EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle),
1205                   -std::sin(expectedRotationAngle),
1206                   0.0,
1207                   0.0,
1208                   to,
1209                   ERROR_THRESHOLD);
1210  EXPECT_ROW2_NEAR(std::sin(expectedRotationAngle),
1211                   std::cos(expectedRotationAngle),
1212                   0.0,
1213                   0.0,
1214                   to,
1215                   ERROR_THRESHOLD);
1216  EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to, ERROR_THRESHOLD);
1217  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1218
1219  to = Transform();
1220  to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1221  to.Blend(from, 1.0);
1222  EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1223  EXPECT_ROW2_NEAR(1.0,  0.0, 0.0, 0.0, to, ERROR_THRESHOLD);
1224  EXPECT_ROW3_NEAR(0.0,  0.0, 1.0, 0.0, to, ERROR_THRESHOLD);
1225  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
1226}
1227
1228TEST(XFormTest, VerifyBlendForCompositeTransform) {
1229  // Verify that the.Blending was done with a decomposition in correct order
1230  // by blending a composite transform. Using matrix x vector notation
1231  // (Ax = b, where x is column vector), the ordering should be:
1232  // perspective * translation * rotation * skew * scale
1233  //
1234  // It is not as important (or meaningful) to check intermediate
1235  // interpolations; order of operations will be tested well enough by the
1236  // end cases that are easier to specify.
1237
1238  Transform from;
1239  Transform to;
1240
1241  Transform expectedEndOfAnimation;
1242  expectedEndOfAnimation.ApplyPerspectiveDepth(1.0);
1243  expectedEndOfAnimation.Translate3d(10.0, 20.0, 30.0);
1244  expectedEndOfAnimation.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 25.0);
1245  expectedEndOfAnimation.SkewY(45.0);
1246  expectedEndOfAnimation.Scale3d(6.0, 7.0, 8.0);
1247
1248  to = expectedEndOfAnimation;
1249  to.Blend(from, 0.0);
1250  EXPECT_EQ(from, to);
1251
1252  to = expectedEndOfAnimation;
1253  // We short circuit if blend is >= 1, so to check the numerics, we will
1254  // check that we get close to what we expect when we're nearly done
1255  // interpolating.
1256  to.Blend(from, .99999f);
1257
1258  // Recomposing the matrix results in a normalized matrix, so to verify we
1259  // need to normalize the expectedEndOfAnimation before comparing elements.
1260  // Normalizing means dividing everything by expectedEndOfAnimation.m44().
1261  Transform normalizedExpectedEndOfAnimation = expectedEndOfAnimation;
1262  Transform normalizationMatrix;
1263  normalizationMatrix.matrix().set(
1264      0.0,
1265      0.0,
1266      SkDoubleToMScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0)));
1267  normalizationMatrix.matrix().set(
1268      1.0,
1269      1.0,
1270      SkDoubleToMScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0)));
1271  normalizationMatrix.matrix().set(
1272      2.0,
1273      2.0,
1274      SkDoubleToMScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0)));
1275  normalizationMatrix.matrix().set(
1276      3.0,
1277      3.0,
1278      SkDoubleToMScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0)));
1279  normalizedExpectedEndOfAnimation.PreconcatTransform(normalizationMatrix);
1280
1281  EXPECT_TRUE(MatricesAreNearlyEqual(normalizedExpectedEndOfAnimation, to));
1282}
1283
1284TEST(XFormTest, DecomposedTransformCtor) {
1285  DecomposedTransform decomp;
1286  for (int i = 0; i < 3; ++i) {
1287    EXPECT_EQ(0.0, decomp.translate[i]);
1288    EXPECT_EQ(1.0, decomp.scale[i]);
1289    EXPECT_EQ(0.0, decomp.skew[i]);
1290    EXPECT_EQ(0.0, decomp.quaternion[i]);
1291    EXPECT_EQ(0.0, decomp.perspective[i]);
1292  }
1293  EXPECT_EQ(1.0, decomp.quaternion[3]);
1294  EXPECT_EQ(1.0, decomp.perspective[3]);
1295  Transform identity;
1296  Transform composed = ComposeTransform(decomp);
1297  EXPECT_TRUE(MatricesAreNearlyEqual(identity, composed));
1298}
1299
1300TEST(XFormTest, FactorTRS) {
1301  for (int degrees = 0; degrees < 180; ++degrees) {
1302    // build a transformation matrix.
1303    gfx::Transform transform;
1304    transform.Translate(degrees * 2, -degrees * 3);
1305    transform.Rotate(degrees);
1306    transform.Scale(degrees + 1, 2 * degrees + 1);
1307
1308    // factor the matrix
1309    DecomposedTransform decomp;
1310    bool success = DecomposeTransform(&decomp, transform);
1311    EXPECT_TRUE(success);
1312    EXPECT_FLOAT_EQ(decomp.translate[0], degrees * 2);
1313    EXPECT_FLOAT_EQ(decomp.translate[1], -degrees * 3);
1314    double rotation =
1315        std::acos(SkMScalarToDouble(decomp.quaternion[3])) * 360.0 / M_PI;
1316    while (rotation < 0.0)
1317      rotation += 360.0;
1318    while (rotation > 360.0)
1319      rotation -= 360.0;
1320
1321    const float epsilon = 0.00015f;
1322    EXPECT_NEAR(rotation, degrees, epsilon);
1323    EXPECT_NEAR(decomp.scale[0], degrees + 1, epsilon);
1324    EXPECT_NEAR(decomp.scale[1], 2 * degrees + 1, epsilon);
1325  }
1326}
1327
1328TEST(XFormTest, IntegerTranslation) {
1329  gfx::Transform transform;
1330  EXPECT_TRUE(transform.IsIdentityOrIntegerTranslation());
1331
1332  transform.Translate3d(1, 2, 3);
1333  EXPECT_TRUE(transform.IsIdentityOrIntegerTranslation());
1334
1335  transform.MakeIdentity();
1336  transform.Translate3d(-1, -2, -3);
1337  EXPECT_TRUE(transform.IsIdentityOrIntegerTranslation());
1338
1339  transform.MakeIdentity();
1340  transform.Translate3d(4.5f, 0, 0);
1341  EXPECT_FALSE(transform.IsIdentityOrIntegerTranslation());
1342
1343  transform.MakeIdentity();
1344  transform.Translate3d(0, -6.7f, 0);
1345  EXPECT_FALSE(transform.IsIdentityOrIntegerTranslation());
1346
1347  transform.MakeIdentity();
1348  transform.Translate3d(0, 0, 8.9f);
1349  EXPECT_FALSE(transform.IsIdentityOrIntegerTranslation());
1350}
1351
1352TEST(XFormTest, verifyMatrixInversion) {
1353  {
1354    // Invert a translation
1355    gfx::Transform translation;
1356    translation.Translate3d(2.0, 3.0, 4.0);
1357    EXPECT_TRUE(translation.IsInvertible());
1358
1359    gfx::Transform inverse_translation;
1360    bool is_invertible = translation.GetInverse(&inverse_translation);
1361    EXPECT_TRUE(is_invertible);
1362    EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, -2.0f, inverse_translation);
1363    EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, -3.0f, inverse_translation);
1364    EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, -4.0f, inverse_translation);
1365    EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f,  1.0f, inverse_translation);
1366  }
1367
1368  {
1369    // Invert a non-uniform scale
1370    gfx::Transform scale;
1371    scale.Scale3d(4.0, 10.0, 100.0);
1372    EXPECT_TRUE(scale.IsInvertible());
1373
1374    gfx::Transform inverse_scale;
1375    bool is_invertible = scale.GetInverse(&inverse_scale);
1376    EXPECT_TRUE(is_invertible);
1377    EXPECT_ROW1_EQ(0.25f, 0.0f, 0.0f, 0.0f, inverse_scale);
1378    EXPECT_ROW2_EQ(0.0f,  0.1f, 0.0f, 0.0f, inverse_scale);
1379    EXPECT_ROW3_EQ(0.0f,  0.0f, 0.01f, 0.0f, inverse_scale);
1380    EXPECT_ROW4_EQ(0.0f,  0.0f, 0.0f, 1.0f, inverse_scale);
1381  }
1382
1383  {
1384    // Try to invert a matrix that is not invertible.
1385    // The inverse() function should reset the output matrix to identity.
1386    gfx::Transform uninvertible;
1387    uninvertible.matrix().set(0, 0, 0.f);
1388    uninvertible.matrix().set(1, 1, 0.f);
1389    uninvertible.matrix().set(2, 2, 0.f);
1390    uninvertible.matrix().set(3, 3, 0.f);
1391    EXPECT_FALSE(uninvertible.IsInvertible());
1392
1393    gfx::Transform inverse_of_uninvertible;
1394
1395    // Add a scale just to more easily ensure that inverse_of_uninvertible is
1396    // reset to identity.
1397    inverse_of_uninvertible.Scale3d(4.0, 10.0, 100.0);
1398
1399    bool is_invertible = uninvertible.GetInverse(&inverse_of_uninvertible);
1400    EXPECT_FALSE(is_invertible);
1401    EXPECT_TRUE(inverse_of_uninvertible.IsIdentity());
1402    EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, inverse_of_uninvertible);
1403    EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, inverse_of_uninvertible);
1404    EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, inverse_of_uninvertible);
1405    EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, inverse_of_uninvertible);
1406  }
1407}
1408
1409TEST(XFormTest, verifyBackfaceVisibilityBasicCases) {
1410  Transform transform;
1411
1412  transform.MakeIdentity();
1413  EXPECT_FALSE(transform.IsBackFaceVisible());
1414
1415  transform.MakeIdentity();
1416  transform.RotateAboutYAxis(80.0);
1417  EXPECT_FALSE(transform.IsBackFaceVisible());
1418
1419  transform.MakeIdentity();
1420  transform.RotateAboutYAxis(100.0);
1421  EXPECT_TRUE(transform.IsBackFaceVisible());
1422
1423  // Edge case, 90 degree rotation should return false.
1424  transform.MakeIdentity();
1425  transform.RotateAboutYAxis(90.0);
1426  EXPECT_FALSE(transform.IsBackFaceVisible());
1427}
1428
1429TEST(XFormTest, verifyBackfaceVisibilityForPerspective) {
1430  Transform layer_space_to_projection_plane;
1431
1432  // This tests if IsBackFaceVisible works properly under perspective
1433  // transforms.  Specifically, layers that may have their back face visible in
1434  // orthographic projection, may not actually have back face visible under
1435  // perspective projection.
1436
1437  // Case 1: Layer is rotated by slightly more than 90 degrees, at the center
1438  //         of the prespective projection. In this case, the layer's back-side
1439  //         is visible to the camera.
1440  layer_space_to_projection_plane.MakeIdentity();
1441  layer_space_to_projection_plane.ApplyPerspectiveDepth(1.0);
1442  layer_space_to_projection_plane.Translate3d(0.0, 0.0, 0.0);
1443  layer_space_to_projection_plane.RotateAboutYAxis(100.0);
1444  EXPECT_TRUE(layer_space_to_projection_plane.IsBackFaceVisible());
1445
1446  // Case 2: Layer is rotated by slightly more than 90 degrees, but shifted off
1447  //         to the side of the camera. Because of the wide field-of-view, the
1448  //         layer's front side is still visible.
1449  //
1450  //                       |<-- front side of layer is visible to camera
1451  //                    \  |            /
1452  //                     \ |           /
1453  //                      \|          /
1454  //                       |         /
1455  //                       |\       /<-- camera field of view
1456  //                       | \     /
1457  // back side of layer -->|  \   /
1458  //                           \./ <-- camera origin
1459  //
1460  layer_space_to_projection_plane.MakeIdentity();
1461  layer_space_to_projection_plane.ApplyPerspectiveDepth(1.0);
1462  layer_space_to_projection_plane.Translate3d(-10.0, 0.0, 0.0);
1463  layer_space_to_projection_plane.RotateAboutYAxis(100.0);
1464  EXPECT_FALSE(layer_space_to_projection_plane.IsBackFaceVisible());
1465
1466  // Case 3: Additionally rotating the layer by 180 degrees should of course
1467  //         show the opposite result of case 2.
1468  layer_space_to_projection_plane.RotateAboutYAxis(180.0);
1469  EXPECT_TRUE(layer_space_to_projection_plane.IsBackFaceVisible());
1470}
1471
1472TEST(XFormTest, verifyDefaultConstructorCreatesIdentityMatrix) {
1473  Transform A;
1474  EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1475  EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1476  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1477  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1478  EXPECT_TRUE(A.IsIdentity());
1479}
1480
1481TEST(XFormTest, verifyCopyConstructor) {
1482  Transform A;
1483  InitializeTestMatrix(&A);
1484
1485  // Copy constructor should produce exact same elements as matrix A.
1486  Transform B(A);
1487  EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, B);
1488  EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, B);
1489  EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, B);
1490  EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, B);
1491}
1492
1493TEST(XFormTest, verifyConstructorFor16Elements) {
1494  Transform transform(1.0, 2.0, 3.0, 4.0,
1495                      5.0, 6.0, 7.0, 8.0,
1496                      9.0, 10.0, 11.0, 12.0,
1497                      13.0, 14.0, 15.0, 16.0);
1498
1499  EXPECT_ROW1_EQ(1.0f, 2.0f, 3.0f, 4.0f, transform);
1500  EXPECT_ROW2_EQ(5.0f, 6.0f, 7.0f, 8.0f, transform);
1501  EXPECT_ROW3_EQ(9.0f, 10.0f, 11.0f, 12.0f, transform);
1502  EXPECT_ROW4_EQ(13.0f, 14.0f, 15.0f, 16.0f, transform);
1503}
1504
1505TEST(XFormTest, verifyConstructorFor2dElements) {
1506  Transform transform(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);
1507
1508  EXPECT_ROW1_EQ(1.0f, 2.0f, 0.0f, 5.0f, transform);
1509  EXPECT_ROW2_EQ(3.0f, 4.0f, 0.0f, 6.0f, transform);
1510  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, transform);
1511  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, transform);
1512}
1513
1514
1515TEST(XFormTest, verifyAssignmentOperator) {
1516  Transform A;
1517  InitializeTestMatrix(&A);
1518  Transform B;
1519  InitializeTestMatrix2(&B);
1520  Transform C;
1521  InitializeTestMatrix2(&C);
1522  C = B = A;
1523
1524  // Both B and C should now have been re-assigned to the value of A.
1525  EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, B);
1526  EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, B);
1527  EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, B);
1528  EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, B);
1529
1530  EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, C);
1531  EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, C);
1532  EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, C);
1533  EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, C);
1534}
1535
1536TEST(XFormTest, verifyEqualsBooleanOperator) {
1537  Transform A;
1538  InitializeTestMatrix(&A);
1539
1540  Transform B;
1541  InitializeTestMatrix(&B);
1542  EXPECT_TRUE(A == B);
1543
1544  // Modifying multiple elements should cause equals operator to return false.
1545  Transform C;
1546  InitializeTestMatrix2(&C);
1547  EXPECT_FALSE(A == C);
1548
1549  // Modifying any one individual element should cause equals operator to
1550  // return false.
1551  Transform D;
1552  D = A;
1553  D.matrix().set(0, 0, 0.f);
1554  EXPECT_FALSE(A == D);
1555
1556  D = A;
1557  D.matrix().set(1, 0, 0.f);
1558  EXPECT_FALSE(A == D);
1559
1560  D = A;
1561  D.matrix().set(2, 0, 0.f);
1562  EXPECT_FALSE(A == D);
1563
1564  D = A;
1565  D.matrix().set(3, 0, 0.f);
1566  EXPECT_FALSE(A == D);
1567
1568  D = A;
1569  D.matrix().set(0, 1, 0.f);
1570  EXPECT_FALSE(A == D);
1571
1572  D = A;
1573  D.matrix().set(1, 1, 0.f);
1574  EXPECT_FALSE(A == D);
1575
1576  D = A;
1577  D.matrix().set(2, 1, 0.f);
1578  EXPECT_FALSE(A == D);
1579
1580  D = A;
1581  D.matrix().set(3, 1, 0.f);
1582  EXPECT_FALSE(A == D);
1583
1584  D = A;
1585  D.matrix().set(0, 2, 0.f);
1586  EXPECT_FALSE(A == D);
1587
1588  D = A;
1589  D.matrix().set(1, 2, 0.f);
1590  EXPECT_FALSE(A == D);
1591
1592  D = A;
1593  D.matrix().set(2, 2, 0.f);
1594  EXPECT_FALSE(A == D);
1595
1596  D = A;
1597  D.matrix().set(3, 2, 0.f);
1598  EXPECT_FALSE(A == D);
1599
1600  D = A;
1601  D.matrix().set(0, 3, 0.f);
1602  EXPECT_FALSE(A == D);
1603
1604  D = A;
1605  D.matrix().set(1, 3, 0.f);
1606  EXPECT_FALSE(A == D);
1607
1608  D = A;
1609  D.matrix().set(2, 3, 0.f);
1610  EXPECT_FALSE(A == D);
1611
1612  D = A;
1613  D.matrix().set(3, 3, 0.f);
1614  EXPECT_FALSE(A == D);
1615}
1616
1617TEST(XFormTest, verifyMultiplyOperator) {
1618  Transform A;
1619  InitializeTestMatrix(&A);
1620
1621  Transform B;
1622  InitializeTestMatrix2(&B);
1623
1624  Transform C = A * B;
1625  EXPECT_ROW1_EQ(2036.0f, 2292.0f, 2548.0f, 2804.0f, C);
1626  EXPECT_ROW2_EQ(2162.0f, 2434.0f, 2706.0f, 2978.0f, C);
1627  EXPECT_ROW3_EQ(2288.0f, 2576.0f, 2864.0f, 3152.0f, C);
1628  EXPECT_ROW4_EQ(2414.0f, 2718.0f, 3022.0f, 3326.0f, C);
1629
1630  // Just an additional sanity check; matrix multiplication is not commutative.
1631  EXPECT_FALSE(A * B == B * A);
1632}
1633
1634TEST(XFormTest, verifyMultiplyAndAssignOperator) {
1635  Transform A;
1636  InitializeTestMatrix(&A);
1637
1638  Transform B;
1639  InitializeTestMatrix2(&B);
1640
1641  A *= B;
1642  EXPECT_ROW1_EQ(2036.0f, 2292.0f, 2548.0f, 2804.0f, A);
1643  EXPECT_ROW2_EQ(2162.0f, 2434.0f, 2706.0f, 2978.0f, A);
1644  EXPECT_ROW3_EQ(2288.0f, 2576.0f, 2864.0f, 3152.0f, A);
1645  EXPECT_ROW4_EQ(2414.0f, 2718.0f, 3022.0f, 3326.0f, A);
1646
1647  // Just an additional sanity check; matrix multiplication is not commutative.
1648  Transform C = A;
1649  C *= B;
1650  Transform D = B;
1651  D *= A;
1652  EXPECT_FALSE(C == D);
1653}
1654
1655TEST(XFormTest, verifyMatrixMultiplication) {
1656  Transform A;
1657  InitializeTestMatrix(&A);
1658
1659  Transform B;
1660  InitializeTestMatrix2(&B);
1661
1662  A.PreconcatTransform(B);
1663  EXPECT_ROW1_EQ(2036.0f, 2292.0f, 2548.0f, 2804.0f, A);
1664  EXPECT_ROW2_EQ(2162.0f, 2434.0f, 2706.0f, 2978.0f, A);
1665  EXPECT_ROW3_EQ(2288.0f, 2576.0f, 2864.0f, 3152.0f, A);
1666  EXPECT_ROW4_EQ(2414.0f, 2718.0f, 3022.0f, 3326.0f, A);
1667}
1668
1669TEST(XFormTest, verifyMakeIdentiy) {
1670  Transform A;
1671  InitializeTestMatrix(&A);
1672  A.MakeIdentity();
1673  EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1674  EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1675  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1676  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1677  EXPECT_TRUE(A.IsIdentity());
1678}
1679
1680TEST(XFormTest, verifyTranslate) {
1681  Transform A;
1682  A.Translate(2.0, 3.0);
1683  EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 2.0f, A);
1684  EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 3.0f, A);
1685  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1686  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1687
1688  // Verify that Translate() post-multiplies the existing matrix.
1689  A.MakeIdentity();
1690  A.Scale(5.0, 5.0);
1691  A.Translate(2.0, 3.0);
1692  EXPECT_ROW1_EQ(5.0f, 0.0f, 0.0f, 10.0f, A);
1693  EXPECT_ROW2_EQ(0.0f, 5.0f, 0.0f, 15.0f, A);
1694  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f,  A);
1695  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f,  A);
1696}
1697
1698TEST(XFormTest, verifyTranslate3d) {
1699  Transform A;
1700  A.Translate3d(2.0, 3.0, 4.0);
1701  EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 2.0f, A);
1702  EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 3.0f, A);
1703  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 4.0f, A);
1704  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1705
1706  // Verify that Translate3d() post-multiplies the existing matrix.
1707  A.MakeIdentity();
1708  A.Scale3d(6.0, 7.0, 8.0);
1709  A.Translate3d(2.0, 3.0, 4.0);
1710  EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 12.0f, A);
1711  EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 21.0f, A);
1712  EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 32.0f, A);
1713  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f,  A);
1714}
1715
1716TEST(XFormTest, verifyScale) {
1717  Transform A;
1718  A.Scale(6.0, 7.0);
1719  EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 0.0f, A);
1720  EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 0.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 Scale() post-multiplies the existing matrix.
1725  A.MakeIdentity();
1726  A.Translate3d(2.0, 3.0, 4.0);
1727  A.Scale(6.0, 7.0);
1728  EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 2.0f, A);
1729  EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 3.0f, A);
1730  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 4.0f, A);
1731  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1732}
1733
1734TEST(XFormTest, verifyScale3d) {
1735  Transform A;
1736  A.Scale3d(6.0, 7.0, 8.0);
1737  EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 0.0f, A);
1738  EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 0.0f, A);
1739  EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
1740  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1741
1742  // Verify that scale3d() post-multiplies the existing matrix.
1743  A.MakeIdentity();
1744  A.Translate3d(2.0, 3.0, 4.0);
1745  A.Scale3d(6.0, 7.0, 8.0);
1746  EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 2.0f, A);
1747  EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 3.0f, A);
1748  EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 4.0f, A);
1749  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1750}
1751
1752TEST(XFormTest, verifyRotate) {
1753  Transform A;
1754  A.Rotate(90.0);
1755  EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1756  EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
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 Rotate() post-multiplies the existing matrix.
1761  A.MakeIdentity();
1762  A.Scale3d(6.0, 7.0, 8.0);
1763  A.Rotate(90.0);
1764  EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1765  EXPECT_ROW2_NEAR(7.0, 0.0,  0.0, 0.0, A, ERROR_THRESHOLD);
1766  EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
1767  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1768}
1769
1770TEST(XFormTest, verifyRotateAboutXAxis) {
1771  Transform A;
1772  double sin45 = 0.5 * sqrt(2.0);
1773  double cos45 = sin45;
1774
1775  A.MakeIdentity();
1776  A.RotateAboutXAxis(90.0);
1777  EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1778  EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, A, ERROR_THRESHOLD);
1779  EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1780  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1781
1782  A.MakeIdentity();
1783  A.RotateAboutXAxis(45.0);
1784  EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1785  EXPECT_ROW2_NEAR(0.0, cos45, -sin45, 0.0, A, ERROR_THRESHOLD);
1786  EXPECT_ROW3_NEAR(0.0, sin45, cos45, 0.0, A, ERROR_THRESHOLD);
1787  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1788
1789  // Verify that RotateAboutXAxis(angle) post-multiplies the existing matrix.
1790  A.MakeIdentity();
1791  A.Scale3d(6.0, 7.0, 8.0);
1792  A.RotateAboutXAxis(90.0);
1793  EXPECT_ROW1_NEAR(6.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1794  EXPECT_ROW2_NEAR(0.0, 0.0, -7.0, 0.0, A, ERROR_THRESHOLD);
1795  EXPECT_ROW3_NEAR(0.0, 8.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1796  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1797}
1798
1799TEST(XFormTest, verifyRotateAboutYAxis) {
1800  Transform A;
1801  double sin45 = 0.5 * sqrt(2.0);
1802  double cos45 = sin45;
1803
1804  // Note carefully, the expected pattern is inverted compared to rotating
1805  // about x axis or z axis.
1806  A.MakeIdentity();
1807  A.RotateAboutYAxis(90.0);
1808  EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, A, ERROR_THRESHOLD);
1809  EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1810  EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1811  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1812
1813  A.MakeIdentity();
1814  A.RotateAboutYAxis(45.0);
1815  EXPECT_ROW1_NEAR(cos45, 0.0, sin45, 0.0, A, ERROR_THRESHOLD);
1816  EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1817  EXPECT_ROW3_NEAR(-sin45, 0.0, cos45, 0.0, A, ERROR_THRESHOLD);
1818  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1819
1820  // Verify that RotateAboutYAxis(angle) post-multiplies the existing matrix.
1821  A.MakeIdentity();
1822  A.Scale3d(6.0, 7.0, 8.0);
1823  A.RotateAboutYAxis(90.0);
1824  EXPECT_ROW1_NEAR(0.0, 0.0, 6.0, 0.0, A, ERROR_THRESHOLD);
1825  EXPECT_ROW2_NEAR(0.0, 7.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1826  EXPECT_ROW3_NEAR(-8.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1827  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1828}
1829
1830TEST(XFormTest, verifyRotateAboutZAxis) {
1831  Transform A;
1832  double sin45 = 0.5 * sqrt(2.0);
1833  double cos45 = sin45;
1834
1835  A.MakeIdentity();
1836  A.RotateAboutZAxis(90.0);
1837  EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1838  EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1839  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1840  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1841
1842  A.MakeIdentity();
1843  A.RotateAboutZAxis(45.0);
1844  EXPECT_ROW1_NEAR(cos45, -sin45, 0.0, 0.0, A, ERROR_THRESHOLD);
1845  EXPECT_ROW2_NEAR(sin45, cos45, 0.0, 0.0, A, ERROR_THRESHOLD);
1846  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1847  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1848
1849  // Verify that RotateAboutZAxis(angle) post-multiplies the existing matrix.
1850  A.MakeIdentity();
1851  A.Scale3d(6.0, 7.0, 8.0);
1852  A.RotateAboutZAxis(90.0);
1853  EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1854  EXPECT_ROW2_NEAR(7.0, 0.0,  0.0, 0.0, A, ERROR_THRESHOLD);
1855  EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
1856  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1857}
1858
1859TEST(XFormTest, verifyRotateAboutForAlignedAxes) {
1860  Transform A;
1861
1862  // Check rotation about z-axis
1863  A.MakeIdentity();
1864  A.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
1865  EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1866  EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1867  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1868  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1869
1870  // Check rotation about x-axis
1871  A.MakeIdentity();
1872  A.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
1873  EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1874  EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, A, ERROR_THRESHOLD);
1875  EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1876  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1877
1878  // Check rotation about y-axis. Note carefully, the expected pattern is
1879  // inverted compared to rotating about x axis or z axis.
1880  A.MakeIdentity();
1881  A.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
1882  EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, A, ERROR_THRESHOLD);
1883  EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1884  EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1885  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1886
1887  // Verify that rotate3d(axis, angle) post-multiplies the existing matrix.
1888  A.MakeIdentity();
1889  A.Scale3d(6.0, 7.0, 8.0);
1890  A.RotateAboutZAxis(90.0);
1891  EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A, ERROR_THRESHOLD);
1892  EXPECT_ROW2_NEAR(7.0, 0.0,  0.0, 0.0, A, ERROR_THRESHOLD);
1893  EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
1894  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1895}
1896
1897TEST(XFormTest, verifyRotateAboutForArbitraryAxis) {
1898  // Check rotation about an arbitrary non-axis-aligned vector.
1899  Transform A;
1900  A.RotateAbout(Vector3dF(1.0, 1.0, 1.0), 90.0);
1901  EXPECT_ROW1_NEAR(0.3333333333333334258519187,
1902                   -0.2440169358562924717404030,
1903                   0.9106836025229592124219380,
1904                   0.0, A, ERROR_THRESHOLD);
1905  EXPECT_ROW2_NEAR(0.9106836025229592124219380,
1906                   0.3333333333333334258519187,
1907                   -0.2440169358562924717404030,
1908                   0.0, A, ERROR_THRESHOLD);
1909  EXPECT_ROW3_NEAR(-0.2440169358562924717404030,
1910                   0.9106836025229592124219380,
1911                   0.3333333333333334258519187,
1912                   0.0, A, ERROR_THRESHOLD);
1913  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1914}
1915
1916TEST(XFormTest, verifyRotateAboutForDegenerateAxis) {
1917  // Check rotation about a degenerate zero vector.
1918  // It is expected to skip applying the rotation.
1919  Transform A;
1920
1921  A.RotateAbout(Vector3dF(0.0, 0.0, 0.0), 45.0);
1922  // Verify that A remains unchanged.
1923  EXPECT_TRUE(A.IsIdentity());
1924
1925  InitializeTestMatrix(&A);
1926  A.RotateAbout(Vector3dF(0.0, 0.0, 0.0), 35.0);
1927
1928  // Verify that A remains unchanged.
1929  EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, A);
1930  EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, A);
1931  EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, A);
1932  EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, A);
1933}
1934
1935TEST(XFormTest, verifySkewX) {
1936  Transform A;
1937  A.SkewX(45.0);
1938  EXPECT_ROW1_EQ(1.0f, 1.0f, 0.0f, 0.0f, A);
1939  EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
1940  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1941  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1942
1943  // Verify that skewX() post-multiplies the existing matrix. Row 1, column 2,
1944  // would incorrectly have value "7" if the matrix is pre-multiplied instead
1945  // of post-multiplied.
1946  A.MakeIdentity();
1947  A.Scale3d(6.0, 7.0, 8.0);
1948  A.SkewX(45.0);
1949  EXPECT_ROW1_EQ(6.0f, 6.0f, 0.0f, 0.0f, A);
1950  EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 0.0f, A);
1951  EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
1952  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1953}
1954
1955TEST(XFormTest, verifySkewY) {
1956  Transform A;
1957  A.SkewY(45.0);
1958  EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
1959  EXPECT_ROW2_EQ(1.0f, 1.0f, 0.0f, 0.0f, A);
1960  EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
1961  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1962
1963  // Verify that skewY() post-multiplies the existing matrix. Row 2, column 1 ,
1964  // would incorrectly have value "6" if the matrix is pre-multiplied instead
1965  // of post-multiplied.
1966  A.MakeIdentity();
1967  A.Scale3d(6.0, 7.0, 8.0);
1968  A.SkewY(45.0);
1969  EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 0.0f, A);
1970  EXPECT_ROW2_EQ(7.0f, 7.0f, 0.0f, 0.0f, A);
1971  EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
1972  EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
1973}
1974
1975TEST(XFormTest, verifyPerspectiveDepth) {
1976  Transform A;
1977  A.ApplyPerspectiveDepth(1.0);
1978  EXPECT_ROW1_EQ(1.0f, 0.0f,  0.0f, 0.0f, A);
1979  EXPECT_ROW2_EQ(0.0f, 1.0f,  0.0f, 0.0f, A);
1980  EXPECT_ROW3_EQ(0.0f, 0.0f,  1.0f, 0.0f, A);
1981  EXPECT_ROW4_EQ(0.0f, 0.0f, -1.0f, 1.0f, A);
1982
1983  // Verify that PerspectiveDepth() post-multiplies the existing matrix.
1984  A.MakeIdentity();
1985  A.Translate3d(2.0, 3.0, 4.0);
1986  A.ApplyPerspectiveDepth(1.0);
1987  EXPECT_ROW1_EQ(1.0f, 0.0f, -2.0f, 2.0f, A);
1988  EXPECT_ROW2_EQ(0.0f, 1.0f, -3.0f, 3.0f, A);
1989  EXPECT_ROW3_EQ(0.0f, 0.0f, -3.0f, 4.0f, A);
1990  EXPECT_ROW4_EQ(0.0f, 0.0f, -1.0f, 1.0f, A);
1991}
1992
1993TEST(XFormTest, verifyHasPerspective) {
1994  Transform A;
1995  A.ApplyPerspectiveDepth(1.0);
1996  EXPECT_TRUE(A.HasPerspective());
1997
1998  A.MakeIdentity();
1999  A.ApplyPerspectiveDepth(0.0);
2000  EXPECT_FALSE(A.HasPerspective());
2001
2002  A.MakeIdentity();
2003  A.matrix().set(3, 0, -1.f);
2004  EXPECT_TRUE(A.HasPerspective());
2005
2006  A.MakeIdentity();
2007  A.matrix().set(3, 1, -1.f);
2008  EXPECT_TRUE(A.HasPerspective());
2009
2010  A.MakeIdentity();
2011  A.matrix().set(3, 2, -0.3f);
2012  EXPECT_TRUE(A.HasPerspective());
2013
2014  A.MakeIdentity();
2015  A.matrix().set(3, 3, 0.5f);
2016  EXPECT_TRUE(A.HasPerspective());
2017
2018  A.MakeIdentity();
2019  A.matrix().set(3, 3, 0.f);
2020  EXPECT_TRUE(A.HasPerspective());
2021}
2022
2023TEST(XFormTest, verifyIsInvertible) {
2024  Transform A;
2025
2026  // Translations, rotations, scales, skews and arbitrary combinations of them
2027  // are invertible.
2028  A.MakeIdentity();
2029  EXPECT_TRUE(A.IsInvertible());
2030
2031  A.MakeIdentity();
2032  A.Translate3d(2.0, 3.0, 4.0);
2033  EXPECT_TRUE(A.IsInvertible());
2034
2035  A.MakeIdentity();
2036  A.Scale3d(6.0, 7.0, 8.0);
2037  EXPECT_TRUE(A.IsInvertible());
2038
2039  A.MakeIdentity();
2040  A.RotateAboutXAxis(10.0);
2041  A.RotateAboutYAxis(20.0);
2042  A.RotateAboutZAxis(30.0);
2043  EXPECT_TRUE(A.IsInvertible());
2044
2045  A.MakeIdentity();
2046  A.SkewX(45.0);
2047  EXPECT_TRUE(A.IsInvertible());
2048
2049  // A perspective matrix (projection plane at z=0) is invertible. The
2050  // intuitive explanation is that perspective is eqivalent to a skew of the
2051  // w-axis; skews are invertible.
2052  A.MakeIdentity();
2053  A.ApplyPerspectiveDepth(1.0);
2054  EXPECT_TRUE(A.IsInvertible());
2055
2056  // A "pure" perspective matrix derived by similar triangles, with m44() set
2057  // to zero (i.e. camera positioned at the origin), is not invertible.
2058  A.MakeIdentity();
2059  A.ApplyPerspectiveDepth(1.0);
2060  A.matrix().set(3, 3, 0.f);
2061  EXPECT_FALSE(A.IsInvertible());
2062
2063  // Adding more to a non-invertible matrix will not make it invertible in the
2064  // general case.
2065  A.MakeIdentity();
2066  A.ApplyPerspectiveDepth(1.0);
2067  A.matrix().set(3, 3, 0.f);
2068  A.Scale3d(6.0, 7.0, 8.0);
2069  A.RotateAboutXAxis(10.0);
2070  A.RotateAboutYAxis(20.0);
2071  A.RotateAboutZAxis(30.0);
2072  A.Translate3d(6.0, 7.0, 8.0);
2073  EXPECT_FALSE(A.IsInvertible());
2074
2075  // A degenerate matrix of all zeros is not invertible.
2076  A.MakeIdentity();
2077  A.matrix().set(0, 0, 0.f);
2078  A.matrix().set(1, 1, 0.f);
2079  A.matrix().set(2, 2, 0.f);
2080  A.matrix().set(3, 3, 0.f);
2081  EXPECT_FALSE(A.IsInvertible());
2082}
2083
2084TEST(XFormTest, verifyIsIdentity) {
2085  Transform A;
2086
2087  InitializeTestMatrix(&A);
2088  EXPECT_FALSE(A.IsIdentity());
2089
2090  A.MakeIdentity();
2091  EXPECT_TRUE(A.IsIdentity());
2092
2093  // Modifying any one individual element should cause the matrix to no longer
2094  // be identity.
2095  A.MakeIdentity();
2096  A.matrix().set(0, 0, 2.f);
2097  EXPECT_FALSE(A.IsIdentity());
2098
2099  A.MakeIdentity();
2100  A.matrix().set(1, 0, 2.f);
2101  EXPECT_FALSE(A.IsIdentity());
2102
2103  A.MakeIdentity();
2104  A.matrix().set(2, 0, 2.f);
2105  EXPECT_FALSE(A.IsIdentity());
2106
2107  A.MakeIdentity();
2108  A.matrix().set(3, 0, 2.f);
2109  EXPECT_FALSE(A.IsIdentity());
2110
2111  A.MakeIdentity();
2112  A.matrix().set(0, 1, 2.f);
2113  EXPECT_FALSE(A.IsIdentity());
2114
2115  A.MakeIdentity();
2116  A.matrix().set(1, 1, 2.f);
2117  EXPECT_FALSE(A.IsIdentity());
2118
2119  A.MakeIdentity();
2120  A.matrix().set(2, 1, 2.f);
2121  EXPECT_FALSE(A.IsIdentity());
2122
2123  A.MakeIdentity();
2124  A.matrix().set(3, 1, 2.f);
2125  EXPECT_FALSE(A.IsIdentity());
2126
2127  A.MakeIdentity();
2128  A.matrix().set(0, 2, 2.f);
2129  EXPECT_FALSE(A.IsIdentity());
2130
2131  A.MakeIdentity();
2132  A.matrix().set(1, 2, 2.f);
2133  EXPECT_FALSE(A.IsIdentity());
2134
2135  A.MakeIdentity();
2136  A.matrix().set(2, 2, 2.f);
2137  EXPECT_FALSE(A.IsIdentity());
2138
2139  A.MakeIdentity();
2140  A.matrix().set(3, 2, 2.f);
2141  EXPECT_FALSE(A.IsIdentity());
2142
2143  A.MakeIdentity();
2144  A.matrix().set(0, 3, 2.f);
2145  EXPECT_FALSE(A.IsIdentity());
2146
2147  A.MakeIdentity();
2148  A.matrix().set(1, 3, 2.f);
2149  EXPECT_FALSE(A.IsIdentity());
2150
2151  A.MakeIdentity();
2152  A.matrix().set(2, 3, 2.f);
2153  EXPECT_FALSE(A.IsIdentity());
2154
2155  A.MakeIdentity();
2156  A.matrix().set(3, 3, 2.f);
2157  EXPECT_FALSE(A.IsIdentity());
2158}
2159
2160TEST(XFormTest, verifyIsIdentityOrTranslation) {
2161  Transform A;
2162
2163  InitializeTestMatrix(&A);
2164  EXPECT_FALSE(A.IsIdentityOrTranslation());
2165
2166  A.MakeIdentity();
2167  EXPECT_TRUE(A.IsIdentityOrTranslation());
2168
2169  // Modifying any non-translation components should cause
2170  // IsIdentityOrTranslation() to return false. NOTE: (0, 3), (1, 3), and
2171  // (2, 3) are the translation components, so modifying them should still
2172  // return true.
2173  A.MakeIdentity();
2174  A.matrix().set(0, 0, 2.f);
2175  EXPECT_FALSE(A.IsIdentityOrTranslation());
2176
2177  A.MakeIdentity();
2178  A.matrix().set(1, 0, 2.f);
2179  EXPECT_FALSE(A.IsIdentityOrTranslation());
2180
2181  A.MakeIdentity();
2182  A.matrix().set(2, 0, 2.f);
2183  EXPECT_FALSE(A.IsIdentityOrTranslation());
2184
2185  A.MakeIdentity();
2186  A.matrix().set(3, 0, 2.f);
2187  EXPECT_FALSE(A.IsIdentityOrTranslation());
2188
2189  A.MakeIdentity();
2190  A.matrix().set(0, 1, 2.f);
2191  EXPECT_FALSE(A.IsIdentityOrTranslation());
2192
2193  A.MakeIdentity();
2194  A.matrix().set(1, 1, 2.f);
2195  EXPECT_FALSE(A.IsIdentityOrTranslation());
2196
2197  A.MakeIdentity();
2198  A.matrix().set(2, 1, 2.f);
2199  EXPECT_FALSE(A.IsIdentityOrTranslation());
2200
2201  A.MakeIdentity();
2202  A.matrix().set(3, 1, 2.f);
2203  EXPECT_FALSE(A.IsIdentityOrTranslation());
2204
2205  A.MakeIdentity();
2206  A.matrix().set(0, 2, 2.f);
2207  EXPECT_FALSE(A.IsIdentityOrTranslation());
2208
2209  A.MakeIdentity();
2210  A.matrix().set(1, 2, 2.f);
2211  EXPECT_FALSE(A.IsIdentityOrTranslation());
2212
2213  A.MakeIdentity();
2214  A.matrix().set(2, 2, 2.f);
2215  EXPECT_FALSE(A.IsIdentityOrTranslation());
2216
2217  A.MakeIdentity();
2218  A.matrix().set(3, 2, 2.f);
2219  EXPECT_FALSE(A.IsIdentityOrTranslation());
2220
2221  // Note carefully - expecting true here.
2222  A.MakeIdentity();
2223  A.matrix().set(0, 3, 2.f);
2224  EXPECT_TRUE(A.IsIdentityOrTranslation());
2225
2226  // Note carefully - expecting true here.
2227  A.MakeIdentity();
2228  A.matrix().set(1, 3, 2.f);
2229  EXPECT_TRUE(A.IsIdentityOrTranslation());
2230
2231  // Note carefully - expecting true here.
2232  A.MakeIdentity();
2233  A.matrix().set(2, 3, 2.f);
2234  EXPECT_TRUE(A.IsIdentityOrTranslation());
2235
2236  A.MakeIdentity();
2237  A.matrix().set(3, 3, 2.f);
2238  EXPECT_FALSE(A.IsIdentityOrTranslation());
2239}
2240
2241TEST(XFormTest, verifyIsApproximatelyIdentityOrTranslation) {
2242  Transform A;
2243  SkMatrix44& matrix = A.matrix();
2244
2245  // Exact pure translation.
2246  A.MakeIdentity();
2247
2248  // Set translate values to values other than 0 or 1.
2249  matrix.set(0, 3, 3.4f);
2250  matrix.set(1, 3, 4.4f);
2251  matrix.set(2, 3, 5.6f);
2252
2253  EXPECT_TRUE(A.IsApproximatelyIdentityOrTranslation(0));
2254  EXPECT_TRUE(A.IsApproximatelyIdentityOrTranslation(kApproxZero));
2255
2256  // Approximately pure translation.
2257  InitializeApproxIdentityMatrix(&A);
2258
2259  // Some values must be exact.
2260  matrix.set(3, 0, 0);
2261  matrix.set(3, 1, 0);
2262  matrix.set(3, 2, 0);
2263  matrix.set(3, 3, 1);
2264
2265  // Set translate values to values other than 0 or 1.
2266  matrix.set(0, 3, 3.4f);
2267  matrix.set(1, 3, 4.4f);
2268  matrix.set(2, 3, 5.6f);
2269
2270  EXPECT_FALSE(A.IsApproximatelyIdentityOrTranslation(0));
2271  EXPECT_TRUE(A.IsApproximatelyIdentityOrTranslation(kApproxZero));
2272
2273  // Not approximately pure translation.
2274  InitializeApproxIdentityMatrix(&A);
2275
2276  // Some values must be exact.
2277  matrix.set(3, 0, 0);
2278  matrix.set(3, 1, 0);
2279  matrix.set(3, 2, 0);
2280  matrix.set(3, 3, 1);
2281
2282  // Set some values (not translate values) to values other than 0 or 1.
2283  matrix.set(0, 1, 3.4f);
2284  matrix.set(3, 2, 4.4f);
2285  matrix.set(2, 0, 5.6f);
2286
2287  EXPECT_FALSE(A.IsApproximatelyIdentityOrTranslation(0));
2288  EXPECT_FALSE(A.IsApproximatelyIdentityOrTranslation(kApproxZero));
2289}
2290
2291TEST(XFormTest, verifyIsScaleOrTranslation) {
2292  Transform A;
2293
2294  InitializeTestMatrix(&A);
2295  EXPECT_FALSE(A.IsScaleOrTranslation());
2296
2297  A.MakeIdentity();
2298  EXPECT_TRUE(A.IsScaleOrTranslation());
2299
2300  // Modifying any non-scale or non-translation components should cause
2301  // IsScaleOrTranslation() to return false. (0, 0), (1, 1), (2, 2), (0, 3),
2302  // (1, 3), and (2, 3) are the scale and translation components, so
2303  // modifying them should still return true.
2304
2305  // Note carefully - expecting true here.
2306  A.MakeIdentity();
2307  A.matrix().set(0, 0, 2.f);
2308  EXPECT_TRUE(A.IsScaleOrTranslation());
2309
2310  A.MakeIdentity();
2311  A.matrix().set(1, 0, 2.f);
2312  EXPECT_FALSE(A.IsScaleOrTranslation());
2313
2314  A.MakeIdentity();
2315  A.matrix().set(2, 0, 2.f);
2316  EXPECT_FALSE(A.IsScaleOrTranslation());
2317
2318  A.MakeIdentity();
2319  A.matrix().set(3, 0, 2.f);
2320  EXPECT_FALSE(A.IsScaleOrTranslation());
2321
2322  A.MakeIdentity();
2323  A.matrix().set(0, 1, 2.f);
2324  EXPECT_FALSE(A.IsScaleOrTranslation());
2325
2326  // Note carefully - expecting true here.
2327  A.MakeIdentity();
2328  A.matrix().set(1, 1, 2.f);
2329  EXPECT_TRUE(A.IsScaleOrTranslation());
2330
2331  A.MakeIdentity();
2332  A.matrix().set(2, 1, 2.f);
2333  EXPECT_FALSE(A.IsScaleOrTranslation());
2334
2335  A.MakeIdentity();
2336  A.matrix().set(3, 1, 2.f);
2337  EXPECT_FALSE(A.IsScaleOrTranslation());
2338
2339  A.MakeIdentity();
2340  A.matrix().set(0, 2, 2.f);
2341  EXPECT_FALSE(A.IsScaleOrTranslation());
2342
2343  A.MakeIdentity();
2344  A.matrix().set(1, 2, 2.f);
2345  EXPECT_FALSE(A.IsScaleOrTranslation());
2346
2347  // Note carefully - expecting true here.
2348  A.MakeIdentity();
2349  A.matrix().set(2, 2, 2.f);
2350  EXPECT_TRUE(A.IsScaleOrTranslation());
2351
2352  A.MakeIdentity();
2353  A.matrix().set(3, 2, 2.f);
2354  EXPECT_FALSE(A.IsScaleOrTranslation());
2355
2356  // Note carefully - expecting true here.
2357  A.MakeIdentity();
2358  A.matrix().set(0, 3, 2.f);
2359  EXPECT_TRUE(A.IsScaleOrTranslation());
2360
2361  // Note carefully - expecting true here.
2362  A.MakeIdentity();
2363  A.matrix().set(1, 3, 2.f);
2364  EXPECT_TRUE(A.IsScaleOrTranslation());
2365
2366  // Note carefully - expecting true here.
2367  A.MakeIdentity();
2368  A.matrix().set(2, 3, 2.f);
2369  EXPECT_TRUE(A.IsScaleOrTranslation());
2370
2371  A.MakeIdentity();
2372  A.matrix().set(3, 3, 2.f);
2373  EXPECT_FALSE(A.IsScaleOrTranslation());
2374}
2375
2376TEST(XFormTest, verifyFlattenTo2d) {
2377  Transform A;
2378  InitializeTestMatrix(&A);
2379
2380  A.FlattenTo2d();
2381  EXPECT_ROW1_EQ(10.0f, 14.0f, 0.0f, 22.0f, A);
2382  EXPECT_ROW2_EQ(11.0f, 15.0f, 0.0f, 23.0f, A);
2383  EXPECT_ROW3_EQ(0.0f,  0.0f,  1.0f, 0.0f,  A);
2384  EXPECT_ROW4_EQ(13.0f, 17.0f, 0.0f, 25.0f, A);
2385}
2386
2387// Another implementation of Preserves2dAxisAlignment that isn't as fast,
2388// good for testing the faster implementation.
2389static bool EmpiricallyPreserves2dAxisAlignment(const Transform& transform) {
2390  Point3F p1(5.0f, 5.0f, 0.0f);
2391  Point3F p2(10.0f, 5.0f, 0.0f);
2392  Point3F p3(10.0f, 20.0f, 0.0f);
2393  Point3F p4(5.0f, 20.0f, 0.0f);
2394
2395  QuadF test_quad(PointF(p1.x(), p1.y()),
2396                 PointF(p2.x(), p2.y()),
2397                 PointF(p3.x(), p3.y()),
2398                 PointF(p4.x(), p4.y()));
2399  EXPECT_TRUE(test_quad.IsRectilinear());
2400
2401  transform.TransformPoint(&p1);
2402  transform.TransformPoint(&p2);
2403  transform.TransformPoint(&p3);
2404  transform.TransformPoint(&p4);
2405
2406  QuadF transformedQuad(PointF(p1.x(), p1.y()),
2407                        PointF(p2.x(), p2.y()),
2408                        PointF(p3.x(), p3.y()),
2409                        PointF(p4.x(), p4.y()));
2410  return transformedQuad.IsRectilinear();
2411}
2412
2413TEST(XFormTest, Preserves2dAxisAlignment) {
2414  static const struct TestCase {
2415    SkMScalar a; // row 1, column 1
2416    SkMScalar b; // row 1, column 2
2417    SkMScalar c; // row 2, column 1
2418    SkMScalar d; // row 2, column 2
2419    bool expected;
2420  } test_cases[] = {
2421    { 3.f, 0.f,
2422      0.f, 4.f, true }, // basic case
2423    { 0.f, 4.f,
2424      3.f, 0.f, true }, // rotate by 90
2425    { 0.f, 0.f,
2426      0.f, 4.f, true }, // degenerate x
2427    { 3.f, 0.f,
2428      0.f, 0.f, true }, // degenerate y
2429    { 0.f, 0.f,
2430      3.f, 0.f, true }, // degenerate x + rotate by 90
2431    { 0.f, 4.f,
2432      0.f, 0.f, true }, // degenerate y + rotate by 90
2433    { 3.f, 4.f,
2434      0.f, 0.f, false },
2435    { 0.f, 0.f,
2436      3.f, 4.f, false },
2437    { 0.f, 3.f,
2438      0.f, 4.f, false },
2439    { 3.f, 0.f,
2440      4.f, 0.f, false },
2441    { 3.f, 4.f,
2442      5.f, 0.f, false },
2443    { 3.f, 4.f,
2444      0.f, 5.f, false },
2445    { 3.f, 0.f,
2446      4.f, 5.f, false },
2447    { 0.f, 3.f,
2448      4.f, 5.f, false },
2449    { 2.f, 3.f,
2450      4.f, 5.f, false },
2451  };
2452
2453  Transform transform;
2454  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
2455    const TestCase& value = test_cases[i];
2456    transform.MakeIdentity();
2457    transform.matrix().set(0, 0, value.a);
2458    transform.matrix().set(0, 1, value.b);
2459    transform.matrix().set(1, 0, value.c);
2460    transform.matrix().set(1, 1, value.d);
2461
2462    if (value.expected) {
2463      EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2464      EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2465    } else {
2466      EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform));
2467      EXPECT_FALSE(transform.Preserves2dAxisAlignment());
2468    }
2469  }
2470
2471  // Try the same test cases again, but this time make sure that other matrix
2472  // elements (except perspective) have entries, to test that they are ignored.
2473  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
2474    const TestCase& value = test_cases[i];
2475    transform.MakeIdentity();
2476    transform.matrix().set(0, 0, value.a);
2477    transform.matrix().set(0, 1, value.b);
2478    transform.matrix().set(1, 0, value.c);
2479    transform.matrix().set(1, 1, value.d);
2480
2481    transform.matrix().set(0, 2, 1.f);
2482    transform.matrix().set(0, 3, 2.f);
2483    transform.matrix().set(1, 2, 3.f);
2484    transform.matrix().set(1, 3, 4.f);
2485    transform.matrix().set(2, 0, 5.f);
2486    transform.matrix().set(2, 1, 6.f);
2487    transform.matrix().set(2, 2, 7.f);
2488    transform.matrix().set(2, 3, 8.f);
2489
2490    if (value.expected) {
2491      EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2492      EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2493    } else {
2494      EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform));
2495      EXPECT_FALSE(transform.Preserves2dAxisAlignment());
2496    }
2497  }
2498
2499  // Try the same test cases again, but this time add perspective which is
2500  // always assumed to not-preserve axis alignment.
2501  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
2502    const TestCase& value = test_cases[i];
2503    transform.MakeIdentity();
2504    transform.matrix().set(0, 0, value.a);
2505    transform.matrix().set(0, 1, value.b);
2506    transform.matrix().set(1, 0, value.c);
2507    transform.matrix().set(1, 1, value.d);
2508
2509    transform.matrix().set(0, 2, 1.f);
2510    transform.matrix().set(0, 3, 2.f);
2511    transform.matrix().set(1, 2, 3.f);
2512    transform.matrix().set(1, 3, 4.f);
2513    transform.matrix().set(2, 0, 5.f);
2514    transform.matrix().set(2, 1, 6.f);
2515    transform.matrix().set(2, 2, 7.f);
2516    transform.matrix().set(2, 3, 8.f);
2517    transform.matrix().set(3, 0, 9.f);
2518    transform.matrix().set(3, 1, 10.f);
2519    transform.matrix().set(3, 2, 11.f);
2520    transform.matrix().set(3, 3, 12.f);
2521
2522    EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform));
2523    EXPECT_FALSE(transform.Preserves2dAxisAlignment());
2524  }
2525
2526  // Try a few more practical situations to check precision
2527  transform.MakeIdentity();
2528  transform.RotateAboutZAxis(90.0);
2529  EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2530  EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2531
2532  transform.MakeIdentity();
2533  transform.RotateAboutZAxis(180.0);
2534  EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2535  EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2536
2537  transform.MakeIdentity();
2538  transform.RotateAboutZAxis(270.0);
2539  EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2540  EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2541
2542  transform.MakeIdentity();
2543  transform.RotateAboutYAxis(90.0);
2544  EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2545  EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2546
2547  transform.MakeIdentity();
2548  transform.RotateAboutXAxis(90.0);
2549  EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2550  EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2551
2552  transform.MakeIdentity();
2553  transform.RotateAboutZAxis(90.0);
2554  transform.RotateAboutYAxis(90.0);
2555  EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2556  EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2557
2558  transform.MakeIdentity();
2559  transform.RotateAboutZAxis(90.0);
2560  transform.RotateAboutXAxis(90.0);
2561  EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2562  EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2563
2564  transform.MakeIdentity();
2565  transform.RotateAboutYAxis(90.0);
2566  transform.RotateAboutZAxis(90.0);
2567  EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2568  EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2569
2570  transform.MakeIdentity();
2571  transform.RotateAboutZAxis(45.0);
2572  EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform));
2573  EXPECT_FALSE(transform.Preserves2dAxisAlignment());
2574
2575  // 3-d case; In 2d after an orthographic projection, this case does
2576  // preserve 2d axis alignment. But in 3d, it does not preserve axis
2577  // alignment.
2578  transform.MakeIdentity();
2579  transform.RotateAboutYAxis(45.0);
2580  EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2581  EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2582
2583  transform.MakeIdentity();
2584  transform.RotateAboutXAxis(45.0);
2585  EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2586  EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2587
2588  // Perspective cases.
2589  transform.MakeIdentity();
2590  transform.ApplyPerspectiveDepth(10.0);
2591  transform.RotateAboutYAxis(45.0);
2592  EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform));
2593  EXPECT_FALSE(transform.Preserves2dAxisAlignment());
2594
2595  transform.MakeIdentity();
2596  transform.ApplyPerspectiveDepth(10.0);
2597  transform.RotateAboutZAxis(90.0);
2598  EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
2599  EXPECT_TRUE(transform.Preserves2dAxisAlignment());
2600}
2601
2602TEST(XFormTest, To2dTranslation) {
2603  Vector2dF translation(3.f, 7.f);
2604  Transform transform;
2605  transform.Translate(translation.x(), translation.y() + 1);
2606  EXPECT_NE(translation.ToString(), transform.To2dTranslation().ToString());
2607  transform.MakeIdentity();
2608  transform.Translate(translation.x(), translation.y());
2609  EXPECT_EQ(translation.ToString(), transform.To2dTranslation().ToString());
2610}
2611
2612TEST(XFormTest, TransformRect) {
2613  Transform translation;
2614  translation.Translate(3.f, 7.f);
2615  RectF rect(1.f, 2.f, 3.f, 4.f);
2616  RectF expected(4.f, 9.f, 3.f, 4.f);
2617  translation.TransformRect(&rect);
2618  EXPECT_EQ(expected.ToString(), rect.ToString());
2619}
2620
2621TEST(XFormTest, TransformRectReverse) {
2622  Transform translation;
2623  translation.Translate(3.f, 7.f);
2624  RectF rect(1.f, 2.f, 3.f, 4.f);
2625  RectF expected(-2.f, -5.f, 3.f, 4.f);
2626  EXPECT_TRUE(translation.TransformRectReverse(&rect));
2627  EXPECT_EQ(expected.ToString(), rect.ToString());
2628
2629  Transform singular;
2630  singular.Scale3d(0.f, 0.f, 0.f);
2631  EXPECT_FALSE(singular.TransformRectReverse(&rect));
2632}
2633
2634TEST(XFormTest, TransformBox) {
2635  Transform translation;
2636  translation.Translate3d(3.f, 7.f, 6.f);
2637  BoxF box(1.f, 2.f, 3.f, 4.f, 5.f, 6.f);
2638  BoxF expected(4.f, 9.f, 9.f, 4.f, 5.f, 6.f);
2639  translation.TransformBox(&box);
2640  EXPECT_EQ(expected.ToString(), box.ToString());
2641}
2642
2643TEST(XFormTest, TransformBoxReverse) {
2644  Transform translation;
2645  translation.Translate3d(3.f, 7.f, 6.f);
2646  BoxF box(1.f, 2.f, 3.f, 4.f, 5.f, 6.f);
2647  BoxF expected(-2.f, -5.f, -3.f, 4.f, 5.f, 6.f);
2648  EXPECT_TRUE(translation.TransformBoxReverse(&box));
2649  EXPECT_EQ(expected.ToString(), box.ToString());
2650
2651  Transform singular;
2652  singular.Scale3d(0.f, 0.f, 0.f);
2653  EXPECT_FALSE(singular.TransformBoxReverse(&box));
2654}
2655
2656}  // namespace
2657
2658}  // namespace gfx
2659