Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / ui / gfx / transform_unittest.cc
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
24 namespace gfx {
25
26 namespace {
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
73 bool PointsAreNearlyEqual(const Point3F& lhs,
74                           const Point3F& rhs) {
75   float epsilon = 0.0001f;
76   return lhs.SquaredDistanceTo(rhs) < epsilon;
77 }
78
79 bool 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
92 void 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
118 void 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
144 const SkMScalar kApproxZero =
145     SkFloatToMScalar(std::numeric_limits<float>::epsilon());
146 const SkMScalar kApproxOne = 1 - kApproxZero;
147
148 void 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
178 TEST(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
212 TEST(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
246 TEST(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
274 TEST(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
305 TEST(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
354 TEST(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
402 TEST(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
439 TEST(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
474 TEST(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
503 TEST(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
535 TEST(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
590 TEST(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
646 TEST(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
685 TEST(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
702 TEST(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
715 TEST(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
744 TEST(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
781 TEST(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
817 TEST(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
830 TEST(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
845 TEST(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
864 TEST(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
879 TEST(XFormTest, BlendIdentity) {
880   Transform from;
881   Transform to;
882   EXPECT_TRUE(to.Blend(from, 0.5));
883   EXPECT_EQ(to, from);
884 }
885
886 TEST(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
893 TEST(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
928 TEST(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
963 TEST(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
998 TEST(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
1076 TEST(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
1144 TEST(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
1207 TEST(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
1264 TEST(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
1320 TEST(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
1336 TEST(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
1364 TEST(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
1388 TEST(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
1445 TEST(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
1465 TEST(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
1508 TEST(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
1517 TEST(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
1529 TEST(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
1541 TEST(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
1551 TEST(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
1572 TEST(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
1653 TEST(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
1670 TEST(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
1691 TEST(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
1705 TEST(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
1716 TEST(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
1734 TEST(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
1752 TEST(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
1770 TEST(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
1788 TEST(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
1806 TEST(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
1835 TEST(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
1866 TEST(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
1895 TEST(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
1933 TEST(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
1952 TEST(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
1971 TEST(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
1991 TEST(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
2011 TEST(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
2029 TEST(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
2059 TEST(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
2120 TEST(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
2196 TEST(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
2277 TEST(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
2327 TEST(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
2412 TEST(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.
2425 static 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
2449 TEST(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
2638 TEST(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
2648 TEST(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
2657 TEST(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
2670 TEST(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
2679 TEST(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