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