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