1 // Copyright 2017 PDFium 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 #include "core/fxcrt/fx_coordinates.h"
6 
7 #include <limits>
8 #include <vector>
9 
10 #include "testing/gtest/include/gtest/gtest.h"
11 
12 namespace {
13 
14 constexpr float kMinFloat = std::numeric_limits<float>::min();
15 constexpr int kMaxInt = std::numeric_limits<int>::max();
16 constexpr int kMinInt = std::numeric_limits<int>::min();
17 constexpr float kMinIntAsFloat = static_cast<float>(kMinInt);
18 constexpr float kMaxIntAsFloat = static_cast<float>(kMaxInt);
19 
20 }  // namespace
21 
TEST(CFX_FloatRect,FromFXRect)22 TEST(CFX_FloatRect, FromFXRect) {
23   FX_RECT downwards(10, 20, 30, 40);
24   CFX_FloatRect rect(downwards);
25   EXPECT_FLOAT_EQ(rect.left, 10.0f);
26   EXPECT_FLOAT_EQ(rect.bottom, 20.0f);
27   EXPECT_FLOAT_EQ(rect.right, 30.0f);
28   EXPECT_FLOAT_EQ(rect.top, 40.0f);
29 }
30 
TEST(CFX_FloatRect,GetBBox)31 TEST(CFX_FloatRect, GetBBox) {
32   CFX_FloatRect rect = CFX_FloatRect::GetBBox(nullptr, 0);
33   EXPECT_FLOAT_EQ(0.0f, rect.left);
34   EXPECT_FLOAT_EQ(0.0f, rect.bottom);
35   EXPECT_FLOAT_EQ(0.0f, rect.right);
36   EXPECT_FLOAT_EQ(0.0f, rect.top);
37 
38   std::vector<CFX_PointF> data;
39   data.emplace_back(0.0f, 0.0f);
40   rect = CFX_FloatRect::GetBBox(data.data(), 0);
41   EXPECT_FLOAT_EQ(0.0f, rect.left);
42   EXPECT_FLOAT_EQ(0.0f, rect.bottom);
43   EXPECT_FLOAT_EQ(0.0f, rect.right);
44   EXPECT_FLOAT_EQ(0.0f, rect.top);
45   rect = CFX_FloatRect::GetBBox(data.data(), data.size());
46   EXPECT_FLOAT_EQ(0.0f, rect.left);
47   EXPECT_FLOAT_EQ(0.0f, rect.bottom);
48   EXPECT_FLOAT_EQ(0.0f, rect.right);
49   EXPECT_FLOAT_EQ(0.0f, rect.top);
50 
51   data.emplace_back(2.5f, 6.2f);
52   data.emplace_back(1.5f, 6.2f);
53   rect = CFX_FloatRect::GetBBox(data.data(), 2);
54   EXPECT_FLOAT_EQ(0.0f, rect.left);
55   EXPECT_FLOAT_EQ(0.0f, rect.bottom);
56   EXPECT_FLOAT_EQ(2.5f, rect.right);
57   EXPECT_FLOAT_EQ(6.2f, rect.top);
58 
59   rect = CFX_FloatRect::GetBBox(data.data(), data.size());
60   EXPECT_FLOAT_EQ(0.0f, rect.left);
61   EXPECT_FLOAT_EQ(0.0f, rect.bottom);
62   EXPECT_FLOAT_EQ(2.5f, rect.right);
63   EXPECT_FLOAT_EQ(6.2f, rect.top);
64 
65   data.emplace_back(2.5f, 6.3f);
66   rect = CFX_FloatRect::GetBBox(data.data(), data.size());
67   EXPECT_FLOAT_EQ(0.0f, rect.left);
68   EXPECT_FLOAT_EQ(0.0f, rect.bottom);
69   EXPECT_FLOAT_EQ(2.5f, rect.right);
70   EXPECT_FLOAT_EQ(6.3f, rect.top);
71 
72   data.emplace_back(-3.0f, 6.3f);
73   rect = CFX_FloatRect::GetBBox(data.data(), data.size());
74   EXPECT_FLOAT_EQ(-3.0f, rect.left);
75   EXPECT_FLOAT_EQ(0.0f, rect.bottom);
76   EXPECT_FLOAT_EQ(2.5f, rect.right);
77   EXPECT_FLOAT_EQ(6.3f, rect.top);
78 
79   data.emplace_back(4.0f, -8.0f);
80   rect = CFX_FloatRect::GetBBox(data.data(), data.size());
81   EXPECT_FLOAT_EQ(-3.0f, rect.left);
82   EXPECT_FLOAT_EQ(-8.0f, rect.bottom);
83   EXPECT_FLOAT_EQ(4.0f, rect.right);
84   EXPECT_FLOAT_EQ(6.3f, rect.top);
85 }
86 
TEST(CFX_FloatRect,GetInnerRect)87 TEST(CFX_FloatRect, GetInnerRect) {
88   FX_RECT inner_rect;
89   CFX_FloatRect rect;
90 
91   inner_rect = rect.GetInnerRect();
92   EXPECT_EQ(0, inner_rect.left);
93   EXPECT_EQ(0, inner_rect.bottom);
94   EXPECT_EQ(0, inner_rect.right);
95   EXPECT_EQ(0, inner_rect.top);
96 
97   // Function converts from float to int using floor() for top and right, and
98   // ceil() for left and bottom.
99   rect = CFX_FloatRect(-1.1f, 3.6f, 4.4f, -5.7f);
100   inner_rect = rect.GetInnerRect();
101   EXPECT_EQ(-1, inner_rect.left);
102   EXPECT_EQ(4, inner_rect.bottom);
103   EXPECT_EQ(4, inner_rect.right);
104   EXPECT_EQ(-6, inner_rect.top);
105 
106   rect = CFX_FloatRect(kMinFloat, kMinFloat, kMinFloat, kMinFloat);
107   inner_rect = rect.GetInnerRect();
108   EXPECT_EQ(0, inner_rect.left);
109   EXPECT_EQ(1, inner_rect.bottom);
110   EXPECT_EQ(1, inner_rect.right);
111   EXPECT_EQ(0, inner_rect.top);
112 
113   rect = CFX_FloatRect(-kMinFloat, -kMinFloat, -kMinFloat, -kMinFloat);
114   inner_rect = rect.GetInnerRect();
115   EXPECT_EQ(-1, inner_rect.left);
116   EXPECT_EQ(0, inner_rect.bottom);
117   EXPECT_EQ(0, inner_rect.right);
118   EXPECT_EQ(-1, inner_rect.top);
119 
120   // Check at limits of integer range. When saturated would expect to get values
121   // that are clamped to the limits of integers, but instead it is returning all
122   // negative values that represent a rectangle as a dot in a far reach of the
123   // negative coordinate space.  Related to crbug.com/1019026
124   rect = CFX_FloatRect(kMinIntAsFloat, kMinIntAsFloat, kMaxIntAsFloat,
125                        kMaxIntAsFloat);
126   inner_rect = rect.GetInnerRect();
127   EXPECT_EQ(kMinInt, inner_rect.left);
128   EXPECT_EQ(kMaxInt, inner_rect.bottom);
129   EXPECT_EQ(kMaxInt, inner_rect.right);
130   EXPECT_EQ(kMinInt, inner_rect.top);
131 
132   rect = CFX_FloatRect(kMinIntAsFloat - 1.0f, kMinIntAsFloat - 1.0f,
133                        kMaxIntAsFloat + 1.0f, kMaxIntAsFloat + 1.0f);
134   inner_rect = rect.GetInnerRect();
135   EXPECT_EQ(kMinInt, inner_rect.left);
136   EXPECT_EQ(kMaxInt, inner_rect.bottom);
137   EXPECT_EQ(kMaxInt, inner_rect.right);
138   EXPECT_EQ(kMinInt, inner_rect.top);
139 }
140 
TEST(CFX_FloatRect,GetOuterRect)141 TEST(CFX_FloatRect, GetOuterRect) {
142   FX_RECT outer_rect;
143   CFX_FloatRect rect;
144 
145   outer_rect = rect.GetOuterRect();
146   EXPECT_EQ(0, outer_rect.left);
147   EXPECT_EQ(0, outer_rect.bottom);
148   EXPECT_EQ(0, outer_rect.right);
149   EXPECT_EQ(0, outer_rect.top);
150 
151   // Function converts from float to int using floor() for left and bottom, and
152   // ceil() for right and top.
153   rect = CFX_FloatRect(-1.1f, 3.6f, 4.4f, -5.7f);
154   outer_rect = rect.GetOuterRect();
155   EXPECT_EQ(-2, outer_rect.left);
156   EXPECT_EQ(3, outer_rect.bottom);
157   EXPECT_EQ(5, outer_rect.right);
158   EXPECT_EQ(-5, outer_rect.top);
159 
160   rect = CFX_FloatRect(kMinFloat, kMinFloat, kMinFloat, kMinFloat);
161   outer_rect = rect.GetOuterRect();
162   EXPECT_EQ(0, outer_rect.left);
163   EXPECT_EQ(1, outer_rect.bottom);
164   EXPECT_EQ(1, outer_rect.right);
165   EXPECT_EQ(0, outer_rect.top);
166 
167   rect = CFX_FloatRect(-kMinFloat, -kMinFloat, -kMinFloat, -kMinFloat);
168   outer_rect = rect.GetOuterRect();
169   EXPECT_EQ(-1, outer_rect.left);
170   EXPECT_EQ(0, outer_rect.bottom);
171   EXPECT_EQ(0, outer_rect.right);
172   EXPECT_EQ(-1, outer_rect.top);
173 
174   // Check at limits of integer range. When saturated would expect to get values
175   // that are clamped to the limits of integers.
176   rect = CFX_FloatRect(kMinIntAsFloat, kMinIntAsFloat, kMaxIntAsFloat,
177                        kMaxIntAsFloat);
178   outer_rect = rect.GetOuterRect();
179   EXPECT_EQ(kMinInt, outer_rect.left);
180   EXPECT_EQ(kMaxInt, outer_rect.bottom);
181   EXPECT_EQ(kMaxInt, outer_rect.right);
182   EXPECT_EQ(kMinInt, outer_rect.top);
183 
184   rect = CFX_FloatRect(kMinIntAsFloat - 1.0f, kMinIntAsFloat - 1.0f,
185                        kMaxIntAsFloat + 1.0f, kMaxIntAsFloat + 1.0f);
186   outer_rect = rect.GetOuterRect();
187   EXPECT_EQ(kMinInt, outer_rect.left);
188   EXPECT_EQ(kMaxInt, outer_rect.bottom);
189   EXPECT_EQ(kMaxInt, outer_rect.right);
190   EXPECT_EQ(kMinInt, outer_rect.top);
191 }
192 
TEST(CFX_FloatRect,Normalize)193 TEST(CFX_FloatRect, Normalize) {
194   CFX_FloatRect rect;
195   rect.Normalize();
196   EXPECT_FLOAT_EQ(0.0f, rect.left);
197   EXPECT_FLOAT_EQ(0.0f, rect.bottom);
198   EXPECT_FLOAT_EQ(0.0f, rect.right);
199   EXPECT_FLOAT_EQ(0.0f, rect.top);
200 
201   rect = CFX_FloatRect(-1.0f, -3.0f, 4.5f, 3.2f);
202   rect.Normalize();
203   EXPECT_FLOAT_EQ(-1.0f, rect.left);
204   EXPECT_FLOAT_EQ(-3.0f, rect.bottom);
205   EXPECT_FLOAT_EQ(4.5f, rect.right);
206   EXPECT_FLOAT_EQ(3.2f, rect.top);
207   rect.Scale(-1.0f);
208   rect.Normalize();
209   EXPECT_FLOAT_EQ(-4.5f, rect.left);
210   EXPECT_FLOAT_EQ(-3.2f, rect.bottom);
211   EXPECT_FLOAT_EQ(1.0f, rect.right);
212   EXPECT_FLOAT_EQ(3.0f, rect.top);
213 }
214 
TEST(CFX_FloatRect,Scale)215 TEST(CFX_FloatRect, Scale) {
216   CFX_FloatRect rect(-1.0f, -3.0f, 4.5f, 3.2f);
217   rect.Scale(1.0f);
218   EXPECT_FLOAT_EQ(-1.0f, rect.left);
219   EXPECT_FLOAT_EQ(-3.0f, rect.bottom);
220   EXPECT_FLOAT_EQ(4.5f, rect.right);
221   EXPECT_FLOAT_EQ(3.2f, rect.top);
222   rect.Scale(0.5f);
223   EXPECT_FLOAT_EQ(-0.5, rect.left);
224   EXPECT_FLOAT_EQ(-1.5, rect.bottom);
225   EXPECT_FLOAT_EQ(2.25f, rect.right);
226   EXPECT_FLOAT_EQ(1.6f, rect.top);
227   rect.Scale(2.0f);
228   EXPECT_FLOAT_EQ(-1.0f, rect.left);
229   EXPECT_FLOAT_EQ(-3.0f, rect.bottom);
230   EXPECT_FLOAT_EQ(4.5f, rect.right);
231   EXPECT_FLOAT_EQ(3.2f, rect.top);
232   rect.Scale(-1.0f);
233   EXPECT_FLOAT_EQ(1.0f, rect.left);
234   EXPECT_FLOAT_EQ(3.0f, rect.bottom);
235   EXPECT_FLOAT_EQ(-4.5f, rect.right);
236   EXPECT_FLOAT_EQ(-3.2f, rect.top);
237   rect.Scale(0.0f);
238   EXPECT_FLOAT_EQ(0.0f, rect.left);
239   EXPECT_FLOAT_EQ(0.0f, rect.bottom);
240   EXPECT_FLOAT_EQ(0.0f, rect.right);
241   EXPECT_FLOAT_EQ(0.0f, rect.top);
242 }
243 
TEST(CFX_FloatRect,ScaleEmpty)244 TEST(CFX_FloatRect, ScaleEmpty) {
245   CFX_FloatRect rect;
246   rect.Scale(1.0f);
247   EXPECT_FLOAT_EQ(0.0f, rect.left);
248   EXPECT_FLOAT_EQ(0.0f, rect.bottom);
249   EXPECT_FLOAT_EQ(0.0f, rect.right);
250   EXPECT_FLOAT_EQ(0.0f, rect.top);
251   rect.Scale(0.5f);
252   EXPECT_FLOAT_EQ(0.0f, rect.left);
253   EXPECT_FLOAT_EQ(0.0f, rect.bottom);
254   EXPECT_FLOAT_EQ(0.0f, rect.right);
255   EXPECT_FLOAT_EQ(0.0f, rect.top);
256   rect.Scale(2.0f);
257   EXPECT_FLOAT_EQ(0.0f, rect.left);
258   EXPECT_FLOAT_EQ(0.0f, rect.bottom);
259   EXPECT_FLOAT_EQ(0.0f, rect.right);
260   EXPECT_FLOAT_EQ(0.0f, rect.top);
261   rect.Scale(0.0f);
262   EXPECT_FLOAT_EQ(0.0f, rect.left);
263   EXPECT_FLOAT_EQ(0.0f, rect.bottom);
264   EXPECT_FLOAT_EQ(0.0f, rect.right);
265   EXPECT_FLOAT_EQ(0.0f, rect.top);
266 }
267 
TEST(CFX_FloatRect,ScaleFromCenterPoint)268 TEST(CFX_FloatRect, ScaleFromCenterPoint) {
269   CFX_FloatRect rect(-1.0f, -3.0f, 4.5f, 3.2f);
270   rect.ScaleFromCenterPoint(1.0f);
271   EXPECT_FLOAT_EQ(-1.0f, rect.left);
272   EXPECT_FLOAT_EQ(-3.0f, rect.bottom);
273   EXPECT_FLOAT_EQ(4.5f, rect.right);
274   EXPECT_FLOAT_EQ(3.2f, rect.top);
275   rect.ScaleFromCenterPoint(0.5f);
276   EXPECT_FLOAT_EQ(0.375f, rect.left);
277   EXPECT_FLOAT_EQ(-1.45f, rect.bottom);
278   EXPECT_FLOAT_EQ(3.125f, rect.right);
279   EXPECT_FLOAT_EQ(1.65f, rect.top);
280   rect.ScaleFromCenterPoint(2.0f);
281   EXPECT_FLOAT_EQ(-1.0f, rect.left);
282   EXPECT_FLOAT_EQ(-3.0f, rect.bottom);
283   EXPECT_FLOAT_EQ(4.5f, rect.right);
284   EXPECT_FLOAT_EQ(3.2f, rect.top);
285   rect.ScaleFromCenterPoint(-1.0f);
286   EXPECT_FLOAT_EQ(4.5f, rect.left);
287   EXPECT_FLOAT_EQ(3.2f, rect.bottom);
288   EXPECT_FLOAT_EQ(-1.0f, rect.right);
289   EXPECT_FLOAT_EQ(-3.0f, rect.top);
290   rect.ScaleFromCenterPoint(0.0f);
291   EXPECT_FLOAT_EQ(1.75f, rect.left);
292   EXPECT_NEAR(0.1f, rect.bottom, 0.001f);
293   EXPECT_FLOAT_EQ(1.75f, rect.right);
294   EXPECT_NEAR(0.1f, rect.top, 0.001f);
295 }
296 
TEST(CFX_FloatRect,ScaleFromCenterPointEmpty)297 TEST(CFX_FloatRect, ScaleFromCenterPointEmpty) {
298   CFX_FloatRect rect;
299   rect.ScaleFromCenterPoint(1.0f);
300   EXPECT_FLOAT_EQ(0.0f, rect.left);
301   EXPECT_FLOAT_EQ(0.0f, rect.bottom);
302   EXPECT_FLOAT_EQ(0.0f, rect.right);
303   EXPECT_FLOAT_EQ(0.0f, rect.top);
304   rect.ScaleFromCenterPoint(0.5f);
305   EXPECT_FLOAT_EQ(0.0f, rect.left);
306   EXPECT_FLOAT_EQ(0.0f, rect.bottom);
307   EXPECT_FLOAT_EQ(0.0f, rect.right);
308   EXPECT_FLOAT_EQ(0.0f, rect.top);
309   rect.ScaleFromCenterPoint(2.0f);
310   EXPECT_FLOAT_EQ(0.0f, rect.left);
311   EXPECT_FLOAT_EQ(0.0f, rect.bottom);
312   EXPECT_FLOAT_EQ(0.0f, rect.right);
313   EXPECT_FLOAT_EQ(0.0f, rect.top);
314   rect.ScaleFromCenterPoint(0.0f);
315   EXPECT_FLOAT_EQ(0.0f, rect.left);
316   EXPECT_FLOAT_EQ(0.0f, rect.bottom);
317   EXPECT_FLOAT_EQ(0.0f, rect.right);
318   EXPECT_FLOAT_EQ(0.0f, rect.top);
319 }
320 
321 #ifndef NDEBUG
TEST(CFX_FloatRect,Print)322 TEST(CFX_FloatRect, Print) {
323   std::ostringstream os;
324   CFX_FloatRect rect;
325   os << rect;
326   EXPECT_STREQ("rect[w 0 x h 0 (left 0, bot 0)]", os.str().c_str());
327 
328   os.str("");
329   rect = CFX_FloatRect(10, 20, 14, 23);
330   os << rect;
331   EXPECT_STREQ("rect[w 4 x h 3 (left 10, bot 20)]", os.str().c_str());
332 
333   os.str("");
334   rect = CFX_FloatRect(10.5, 20.5, 14.75, 23.75);
335   os << rect;
336   EXPECT_STREQ("rect[w 4.25 x h 3.25 (left 10.5, bot 20.5)]", os.str().c_str());
337 }
338 
TEST(CFX_RectF,Print)339 TEST(CFX_RectF, Print) {
340   std::ostringstream os;
341   CFX_RectF rect;
342   os << rect;
343   EXPECT_STREQ("rect[w 0 x h 0 (left 0, top 0)]", os.str().c_str());
344 
345   os.str("");
346   rect = CFX_RectF(10, 20, 4, 3);
347   os << rect;
348   EXPECT_STREQ("rect[w 4 x h 3 (left 10, top 20)]", os.str().c_str());
349 
350   os.str("");
351   rect = CFX_RectF(10.5, 20.5, 4.25, 3.25);
352   os << rect;
353   EXPECT_STREQ("rect[w 4.25 x h 3.25 (left 10.5, top 20.5)]", os.str().c_str());
354 }
355 #endif  // NDEBUG
356 
TEST(CFX_Matrix,ReverseIdentity)357 TEST(CFX_Matrix, ReverseIdentity) {
358   CFX_Matrix rev = CFX_Matrix().GetInverse();
359 
360   EXPECT_FLOAT_EQ(1.0, rev.a);
361   EXPECT_FLOAT_EQ(0.0, rev.b);
362   EXPECT_FLOAT_EQ(0.0, rev.c);
363   EXPECT_FLOAT_EQ(1.0, rev.d);
364   EXPECT_FLOAT_EQ(0.0, rev.e);
365   EXPECT_FLOAT_EQ(0.0, rev.f);
366 
367   CFX_PointF expected(2, 3);
368   CFX_PointF result = rev.Transform(CFX_Matrix().Transform(CFX_PointF(2, 3)));
369   EXPECT_FLOAT_EQ(expected.x, result.x);
370   EXPECT_FLOAT_EQ(expected.y, result.y);
371 }
372 
TEST(CFX_Matrix,SetIdentity)373 TEST(CFX_Matrix, SetIdentity) {
374   CFX_Matrix m;
375   EXPECT_FLOAT_EQ(1.0f, m.a);
376   EXPECT_FLOAT_EQ(0.0f, m.b);
377   EXPECT_FLOAT_EQ(0.0f, m.c);
378   EXPECT_FLOAT_EQ(1.0f, m.d);
379   EXPECT_FLOAT_EQ(0.0f, m.e);
380   EXPECT_FLOAT_EQ(0.0f, m.f);
381   EXPECT_TRUE(m.IsIdentity());
382 
383   m.a = -1;
384   EXPECT_FALSE(m.IsIdentity());
385 
386   m = CFX_Matrix();
387   EXPECT_FLOAT_EQ(1.0f, m.a);
388   EXPECT_FLOAT_EQ(0.0f, m.b);
389   EXPECT_FLOAT_EQ(0.0f, m.c);
390   EXPECT_FLOAT_EQ(1.0f, m.d);
391   EXPECT_FLOAT_EQ(0.0f, m.e);
392   EXPECT_FLOAT_EQ(0.0f, m.f);
393   EXPECT_TRUE(m.IsIdentity());
394 }
395 
TEST(CFX_Matrix,GetInverse)396 TEST(CFX_Matrix, GetInverse) {
397   static constexpr float data[6] = {3, 0, 2, 3, 1, 4};
398   CFX_Matrix m(data);
399   CFX_Matrix rev = m.GetInverse();
400 
401   EXPECT_FLOAT_EQ(0.33333334f, rev.a);
402   EXPECT_FLOAT_EQ(0.0f, rev.b);
403   EXPECT_FLOAT_EQ(-0.22222222f, rev.c);
404   EXPECT_FLOAT_EQ(0.33333334f, rev.d);
405   EXPECT_FLOAT_EQ(0.55555556f, rev.e);
406   EXPECT_FLOAT_EQ(-1.3333334f, rev.f);
407 
408   CFX_PointF expected(2, 3);
409   CFX_PointF result = rev.Transform(m.Transform(CFX_PointF(2, 3)));
410   EXPECT_FLOAT_EQ(expected.x, result.x);
411   EXPECT_FLOAT_EQ(expected.y, result.y);
412 }
413 
414 // Note, I think these are a bug and the matrix should be the identity.
TEST(CFX_Matrix,GetInverseCR702041)415 TEST(CFX_Matrix, GetInverseCR702041) {
416   // The determinate is < std::numeric_limits<float>::epsilon()
417   static constexpr float data[6] = {0.947368443f, -0.108947366f, -0.923076928f,
418                                     0.106153846f, 18.0f,         787.929993f};
419   CFX_Matrix m(data);
420   CFX_Matrix rev = m.GetInverse();
421 
422   EXPECT_FLOAT_EQ(14247728.0f, rev.a);
423   EXPECT_FLOAT_EQ(14622668.0f, rev.b);
424   EXPECT_FLOAT_EQ(1.2389329e+08f, rev.c);
425   EXPECT_FLOAT_EQ(1.2715364e+08f, rev.d);
426   EXPECT_FLOAT_EQ(-9.7875698e+10f, rev.e);
427   EXPECT_FLOAT_EQ(-1.0045138e+11f, rev.f);
428 
429   // Should be 2, 3
430   CFX_PointF expected(0, 0);
431   CFX_PointF result = rev.Transform(m.Transform(CFX_PointF(2, 3)));
432   EXPECT_FLOAT_EQ(expected.x, result.x);
433   EXPECT_FLOAT_EQ(expected.y, result.y);
434 }
435 
TEST(CFX_Matrix,GetInverseCR714187)436 TEST(CFX_Matrix, GetInverseCR714187) {
437   // The determinate is < std::numeric_limits<float>::epsilon()
438   static constexpr float data[6] = {0.000037f,  0.0f,        0.0f,
439                                     -0.000037f, 182.413101f, 136.977646f};
440   CFX_Matrix m(data);
441   CFX_Matrix rev = m.GetInverse();
442 
443   EXPECT_FLOAT_EQ(27027.025f, rev.a);
444   EXPECT_FLOAT_EQ(0.0f, rev.b);
445   EXPECT_FLOAT_EQ(0.0f, rev.c);
446   EXPECT_FLOAT_EQ(-27027.025f, rev.d);
447   EXPECT_FLOAT_EQ(-4930083.5f, rev.e);
448   EXPECT_FLOAT_EQ(3702098.2f, rev.f);
449 
450   // Should be 3 ....
451   CFX_PointF expected(2, 2.75);
452   CFX_PointF result = rev.Transform(m.Transform(CFX_PointF(2, 3)));
453   EXPECT_FLOAT_EQ(expected.x, result.x);
454   EXPECT_FLOAT_EQ(expected.y, result.y);
455 }
456 
457 #define EXPECT_NEAR_FIVE_PLACES(a, b) EXPECT_NEAR((a), (b), 1e-5)
458 
TEST(CFX_Matrix,ComposeTransformations)459 TEST(CFX_Matrix, ComposeTransformations) {
460   // sin(FX_PI/2) and cos(FX_PI/2) have a tiny error and are not exactly 1.0f
461   // and 0.0f. The rotation matrix is thus not perfect.
462 
463   CFX_Matrix rotate_90;
464   rotate_90.Rotate(FX_PI / 2);
465   EXPECT_NEAR_FIVE_PLACES(0.0f, rotate_90.a);
466   EXPECT_NEAR_FIVE_PLACES(1.0f, rotate_90.b);
467   EXPECT_NEAR_FIVE_PLACES(-1.0f, rotate_90.c);
468   EXPECT_NEAR_FIVE_PLACES(0.0f, rotate_90.d);
469   EXPECT_FLOAT_EQ(0.0f, rotate_90.e);
470   EXPECT_FLOAT_EQ(0.0f, rotate_90.f);
471 
472   CFX_Matrix translate_23_11;
473   translate_23_11.Translate(23, 11);
474   EXPECT_FLOAT_EQ(1.0f, translate_23_11.a);
475   EXPECT_FLOAT_EQ(0.0f, translate_23_11.b);
476   EXPECT_FLOAT_EQ(0.0f, translate_23_11.c);
477   EXPECT_FLOAT_EQ(1.0f, translate_23_11.d);
478   EXPECT_FLOAT_EQ(23.0f, translate_23_11.e);
479   EXPECT_FLOAT_EQ(11.0f, translate_23_11.f);
480 
481   CFX_Matrix scale_5_13;
482   scale_5_13.Scale(5, 13);
483   EXPECT_FLOAT_EQ(5.0f, scale_5_13.a);
484   EXPECT_FLOAT_EQ(0.0f, scale_5_13.b);
485   EXPECT_FLOAT_EQ(0.0f, scale_5_13.c);
486   EXPECT_FLOAT_EQ(13.0f, scale_5_13.d);
487   EXPECT_FLOAT_EQ(0.0, scale_5_13.e);
488   EXPECT_FLOAT_EQ(0.0, scale_5_13.f);
489 
490   // Apply the transforms to points step by step.
491   CFX_PointF origin_transformed(0, 0);
492   CFX_PointF p_10_20_transformed(10, 20);
493 
494   origin_transformed = rotate_90.Transform(origin_transformed);
495   EXPECT_FLOAT_EQ(0.0f, origin_transformed.x);
496   EXPECT_FLOAT_EQ(0.0f, origin_transformed.y);
497   p_10_20_transformed = rotate_90.Transform(p_10_20_transformed);
498   EXPECT_FLOAT_EQ(-20.0f, p_10_20_transformed.x);
499   EXPECT_FLOAT_EQ(10.0f, p_10_20_transformed.y);
500 
501   origin_transformed = translate_23_11.Transform(origin_transformed);
502   EXPECT_FLOAT_EQ(23.0f, origin_transformed.x);
503   EXPECT_FLOAT_EQ(11.0f, origin_transformed.y);
504   p_10_20_transformed = translate_23_11.Transform(p_10_20_transformed);
505   EXPECT_FLOAT_EQ(3.0f, p_10_20_transformed.x);
506   EXPECT_FLOAT_EQ(21.0f, p_10_20_transformed.y);
507 
508   origin_transformed = scale_5_13.Transform(origin_transformed);
509   EXPECT_FLOAT_EQ(115.0f, origin_transformed.x);
510   EXPECT_FLOAT_EQ(143.0f, origin_transformed.y);
511   p_10_20_transformed = scale_5_13.Transform(p_10_20_transformed);
512   EXPECT_FLOAT_EQ(15.0f, p_10_20_transformed.x);
513   EXPECT_FLOAT_EQ(273.0f, p_10_20_transformed.y);
514 
515   // Apply the transforms to points in the reverse order.
516   origin_transformed = CFX_PointF(0, 0);
517   p_10_20_transformed = CFX_PointF(10, 20);
518 
519   origin_transformed = scale_5_13.Transform(origin_transformed);
520   EXPECT_FLOAT_EQ(0.0f, origin_transformed.x);
521   EXPECT_FLOAT_EQ(0.0f, origin_transformed.y);
522   p_10_20_transformed = scale_5_13.Transform(p_10_20_transformed);
523   EXPECT_FLOAT_EQ(50.0f, p_10_20_transformed.x);
524   EXPECT_FLOAT_EQ(260.0f, p_10_20_transformed.y);
525 
526   origin_transformed = translate_23_11.Transform(origin_transformed);
527   EXPECT_FLOAT_EQ(23.0f, origin_transformed.x);
528   EXPECT_FLOAT_EQ(11.0f, origin_transformed.y);
529   p_10_20_transformed = translate_23_11.Transform(p_10_20_transformed);
530   EXPECT_FLOAT_EQ(73.0f, p_10_20_transformed.x);
531   EXPECT_FLOAT_EQ(271.0f, p_10_20_transformed.y);
532 
533   origin_transformed = rotate_90.Transform(origin_transformed);
534   EXPECT_FLOAT_EQ(-11.0f, origin_transformed.x);
535   EXPECT_FLOAT_EQ(23.0f, origin_transformed.y);
536   p_10_20_transformed = rotate_90.Transform(p_10_20_transformed);
537   EXPECT_FLOAT_EQ(-271.0f, p_10_20_transformed.x);
538   EXPECT_FLOAT_EQ(73.0f, p_10_20_transformed.y);
539 
540   // Compose all transforms.
541   CFX_Matrix m;
542   m.Concat(rotate_90);
543   m.Concat(translate_23_11);
544   m.Concat(scale_5_13);
545   EXPECT_NEAR_FIVE_PLACES(0.0f, m.a);
546   EXPECT_NEAR_FIVE_PLACES(13.0f, m.b);
547   EXPECT_NEAR_FIVE_PLACES(-5.0f, m.c);
548   EXPECT_NEAR_FIVE_PLACES(0.0f, m.d);
549   EXPECT_FLOAT_EQ(115.0, m.e);
550   EXPECT_FLOAT_EQ(143.0, m.f);
551 
552   // Note how the results using the combined matrix are equal to the results
553   // when applying the three original matrices step-by-step.
554   origin_transformed = m.Transform(CFX_PointF(0, 0));
555   EXPECT_FLOAT_EQ(115.0f, origin_transformed.x);
556   EXPECT_FLOAT_EQ(143.0f, origin_transformed.y);
557 
558   p_10_20_transformed = m.Transform(CFX_PointF(10, 20));
559   EXPECT_FLOAT_EQ(15.0f, p_10_20_transformed.x);
560   EXPECT_FLOAT_EQ(273.0f, p_10_20_transformed.y);
561 
562   // Now compose all transforms prepending.
563   m = CFX_Matrix();
564   m = rotate_90 * m;
565   m = translate_23_11 * m;
566   m = scale_5_13 * m;
567   EXPECT_NEAR_FIVE_PLACES(0.0f, m.a);
568   EXPECT_NEAR_FIVE_PLACES(5.0f, m.b);
569   EXPECT_NEAR_FIVE_PLACES(-13.0f, m.c);
570   EXPECT_NEAR_FIVE_PLACES(0.0f, m.d);
571   EXPECT_FLOAT_EQ(-11.0, m.e);
572   EXPECT_FLOAT_EQ(23.0, m.f);
573 
574   // Note how the results using the combined matrix are equal to the results
575   // when applying the three original matrices step-by-step in the reverse
576   // order.
577   origin_transformed = m.Transform(CFX_PointF(0, 0));
578   EXPECT_FLOAT_EQ(-11.0f, origin_transformed.x);
579   EXPECT_FLOAT_EQ(23.0f, origin_transformed.y);
580 
581   p_10_20_transformed = m.Transform(CFX_PointF(10, 20));
582   EXPECT_FLOAT_EQ(-271.0f, p_10_20_transformed.x);
583   EXPECT_FLOAT_EQ(73.0f, p_10_20_transformed.y);
584 }
585 
TEST(CFX_Matrix,TransformRectForRectF)586 TEST(CFX_Matrix, TransformRectForRectF) {
587   CFX_Matrix rotate_90;
588   rotate_90.Rotate(FX_PI / 2);
589 
590   CFX_Matrix scale_5_13;
591   scale_5_13.Scale(5, 13);
592 
593   CFX_RectF rect(10.5f, 20.5f, 4.25f, 3.25f);
594   rect = rotate_90.TransformRect(rect);
595   EXPECT_FLOAT_EQ(-23.75f, rect.Left());
596   EXPECT_FLOAT_EQ(10.5f, rect.Top());
597   EXPECT_FLOAT_EQ(3.25f, rect.Width());
598   EXPECT_FLOAT_EQ(4.25f, rect.Height());
599 
600   rect = scale_5_13.TransformRect(rect);
601   EXPECT_FLOAT_EQ(-118.75f, rect.Left());
602   EXPECT_FLOAT_EQ(136.5f, rect.Top());
603   EXPECT_FLOAT_EQ(16.25f, rect.Width());
604   EXPECT_FLOAT_EQ(55.25f, rect.Height());
605 }
606 
TEST(CFX_Matrix,TransformRectForFloatRect)607 TEST(CFX_Matrix, TransformRectForFloatRect) {
608   CFX_Matrix rotate_90;
609   rotate_90.Rotate(FX_PI / 2);
610 
611   CFX_Matrix scale_5_13;
612   scale_5_13.Scale(5, 13);
613 
614   CFX_FloatRect rect(5.5f, 0.0f, 12.25f, 2.7f);
615   rect = rotate_90.TransformRect(rect);
616   EXPECT_FLOAT_EQ(-2.7f, rect.Left());
617   EXPECT_FLOAT_EQ(5.5f, rect.Bottom());
618   EXPECT_NEAR(0.0f, rect.Right(), 0.00001f);
619   EXPECT_FLOAT_EQ(12.25f, rect.Top());
620 
621   rect = scale_5_13.TransformRect(rect);
622   EXPECT_FLOAT_EQ(-13.5f, rect.Left());
623   EXPECT_FLOAT_EQ(71.5f, rect.Bottom());
624   EXPECT_NEAR(0.0f, rect.Right(), 0.00001f);
625   EXPECT_FLOAT_EQ(159.25f, rect.Top());
626 }
627