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