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