Flutter Impeller
rect_unittests.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter 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 "gtest/gtest.h"
6 
8 
10 
11 namespace impeller {
12 namespace testing {
13 
14 TEST(RectTest, RectEmptyDeclaration) {
15  Rect rect;
16 
17  EXPECT_EQ(rect.GetLeft(), 0.0f);
18  EXPECT_EQ(rect.GetTop(), 0.0f);
19  EXPECT_EQ(rect.GetRight(), 0.0f);
20  EXPECT_EQ(rect.GetBottom(), 0.0f);
21  EXPECT_EQ(rect.GetX(), 0.0f);
22  EXPECT_EQ(rect.GetY(), 0.0f);
23  EXPECT_EQ(rect.GetWidth(), 0.0f);
24  EXPECT_EQ(rect.GetHeight(), 0.0f);
25  EXPECT_TRUE(rect.IsEmpty());
26  EXPECT_TRUE(rect.IsFinite());
27 }
28 
29 TEST(RectTest, IRectEmptyDeclaration) {
30  IRect rect;
31 
32  EXPECT_EQ(rect.GetLeft(), 0);
33  EXPECT_EQ(rect.GetTop(), 0);
34  EXPECT_EQ(rect.GetRight(), 0);
35  EXPECT_EQ(rect.GetBottom(), 0);
36  EXPECT_EQ(rect.GetX(), 0);
37  EXPECT_EQ(rect.GetY(), 0);
38  EXPECT_EQ(rect.GetWidth(), 0);
39  EXPECT_EQ(rect.GetHeight(), 0);
40  EXPECT_TRUE(rect.IsEmpty());
41  // EXPECT_TRUE(rect.IsFinite()); // should fail to compile
42 }
43 
44 TEST(RectTest, RectDefaultConstructor) {
45  Rect rect = Rect();
46 
47  EXPECT_EQ(rect.GetLeft(), 0.0f);
48  EXPECT_EQ(rect.GetTop(), 0.0f);
49  EXPECT_EQ(rect.GetRight(), 0.0f);
50  EXPECT_EQ(rect.GetBottom(), 0.0f);
51  EXPECT_EQ(rect.GetX(), 0.0f);
52  EXPECT_EQ(rect.GetY(), 0.0f);
53  EXPECT_EQ(rect.GetWidth(), 0.0f);
54  EXPECT_EQ(rect.GetHeight(), 0.0f);
55  EXPECT_TRUE(rect.IsEmpty());
56  EXPECT_TRUE(rect.IsFinite());
57 }
58 
59 TEST(RectTest, IRectDefaultConstructor) {
60  IRect rect = IRect();
61 
62  EXPECT_EQ(rect.GetLeft(), 0);
63  EXPECT_EQ(rect.GetTop(), 0);
64  EXPECT_EQ(rect.GetRight(), 0);
65  EXPECT_EQ(rect.GetBottom(), 0);
66  EXPECT_EQ(rect.GetX(), 0);
67  EXPECT_EQ(rect.GetY(), 0);
68  EXPECT_EQ(rect.GetWidth(), 0);
69  EXPECT_EQ(rect.GetHeight(), 0);
70  EXPECT_TRUE(rect.IsEmpty());
71 }
72 
73 TEST(RectTest, RectSimpleLTRB) {
74  // Using fractional-power-of-2 friendly values for equality tests
75  Rect rect = Rect::MakeLTRB(5.125f, 10.25f, 20.625f, 25.375f);
76 
77  EXPECT_EQ(rect.GetLeft(), 5.125f);
78  EXPECT_EQ(rect.GetTop(), 10.25f);
79  EXPECT_EQ(rect.GetRight(), 20.625f);
80  EXPECT_EQ(rect.GetBottom(), 25.375f);
81  EXPECT_EQ(rect.GetX(), 5.125f);
82  EXPECT_EQ(rect.GetY(), 10.25f);
83  EXPECT_EQ(rect.GetWidth(), 15.5f);
84  EXPECT_EQ(rect.GetHeight(), 15.125f);
85  EXPECT_FALSE(rect.IsEmpty());
86  EXPECT_TRUE(rect.IsFinite());
87 }
88 
89 TEST(RectTest, IRectSimpleLTRB) {
90  IRect rect = IRect::MakeLTRB(5, 10, 20, 25);
91 
92  EXPECT_EQ(rect.GetLeft(), 5);
93  EXPECT_EQ(rect.GetTop(), 10);
94  EXPECT_EQ(rect.GetRight(), 20);
95  EXPECT_EQ(rect.GetBottom(), 25);
96  EXPECT_EQ(rect.GetX(), 5);
97  EXPECT_EQ(rect.GetY(), 10);
98  EXPECT_EQ(rect.GetWidth(), 15);
99  EXPECT_EQ(rect.GetHeight(), 15);
100  EXPECT_FALSE(rect.IsEmpty());
101 }
102 
103 TEST(RectTest, RectSimpleXYWH) {
104  // Using fractional-power-of-2 friendly values for equality tests
105  Rect rect = Rect::MakeXYWH(5.125f, 10.25f, 15.5f, 15.125f);
106 
107  EXPECT_EQ(rect.GetLeft(), 5.125f);
108  EXPECT_EQ(rect.GetTop(), 10.25f);
109  EXPECT_EQ(rect.GetRight(), 20.625f);
110  EXPECT_EQ(rect.GetBottom(), 25.375f);
111  EXPECT_EQ(rect.GetX(), 5.125f);
112  EXPECT_EQ(rect.GetY(), 10.25f);
113  EXPECT_EQ(rect.GetWidth(), 15.5f);
114  EXPECT_EQ(rect.GetHeight(), 15.125f);
115  EXPECT_FALSE(rect.IsEmpty());
116  EXPECT_TRUE(rect.IsFinite());
117 }
118 
119 TEST(RectTest, IRectSimpleXYWH) {
120  IRect rect = IRect::MakeXYWH(5, 10, 15, 16);
121 
122  EXPECT_EQ(rect.GetLeft(), 5);
123  EXPECT_EQ(rect.GetTop(), 10);
124  EXPECT_EQ(rect.GetRight(), 20);
125  EXPECT_EQ(rect.GetBottom(), 26);
126  EXPECT_EQ(rect.GetX(), 5);
127  EXPECT_EQ(rect.GetY(), 10);
128  EXPECT_EQ(rect.GetWidth(), 15);
129  EXPECT_EQ(rect.GetHeight(), 16);
130  EXPECT_FALSE(rect.IsEmpty());
131 }
132 
133 TEST(RectTest, RectOverflowXYWH) {
134  auto min = std::numeric_limits<Scalar>::lowest();
135  auto max = std::numeric_limits<Scalar>::max();
136  auto inf = std::numeric_limits<Scalar>::infinity();
137 
138  // 8 cases:
139  // finite X, max W
140  // max X, max W
141  // finite Y, max H
142  // max Y, max H
143  // finite X, min W
144  // min X, min W
145  // finite Y, min H
146  // min Y, min H
147 
148  // a small finite value added to a max value will remain max
149  // a very large finite value (like max) added to max will go to infinity
150 
151  {
152  Rect rect = Rect::MakeXYWH(5.0, 10.0f, max, 15.0f);
153 
154  EXPECT_EQ(rect.GetLeft(), 5.0f);
155  EXPECT_EQ(rect.GetTop(), 10.0f);
156  EXPECT_EQ(rect.GetRight(), max);
157  EXPECT_EQ(rect.GetBottom(), 25.0f);
158  EXPECT_EQ(rect.GetX(), 5.0f);
159  EXPECT_EQ(rect.GetY(), 10.0f);
160  EXPECT_EQ(rect.GetWidth(), max);
161  EXPECT_EQ(rect.GetHeight(), 15.0f);
162  EXPECT_FALSE(rect.IsEmpty());
163  EXPECT_TRUE(rect.IsFinite());
164  }
165 
166  {
167  Rect rect = Rect::MakeXYWH(max, 10.0f, max, 15.0f);
168 
169  EXPECT_EQ(rect.GetLeft(), max);
170  EXPECT_EQ(rect.GetTop(), 10.0f);
171  EXPECT_EQ(rect.GetRight(), inf);
172  EXPECT_EQ(rect.GetBottom(), 25.0f);
173  EXPECT_EQ(rect.GetX(), max);
174  EXPECT_EQ(rect.GetY(), 10.0f);
175  EXPECT_EQ(rect.GetWidth(), inf);
176  EXPECT_EQ(rect.GetHeight(), 15.0f);
177  EXPECT_FALSE(rect.IsEmpty());
178  EXPECT_FALSE(rect.IsFinite());
179  }
180 
181  {
182  Rect rect = Rect::MakeXYWH(5.0f, 10.0f, 20.0f, max);
183 
184  EXPECT_EQ(rect.GetLeft(), 5.0f);
185  EXPECT_EQ(rect.GetTop(), 10.0f);
186  EXPECT_EQ(rect.GetRight(), 25.0f);
187  EXPECT_EQ(rect.GetBottom(), max);
188  EXPECT_EQ(rect.GetX(), 5.0f);
189  EXPECT_EQ(rect.GetY(), 10.0f);
190  EXPECT_EQ(rect.GetWidth(), 20.0f);
191  EXPECT_EQ(rect.GetHeight(), max);
192  EXPECT_FALSE(rect.IsEmpty());
193  EXPECT_TRUE(rect.IsFinite());
194  }
195 
196  {
197  Rect rect = Rect::MakeXYWH(5.0f, max, 20.0f, max);
198 
199  EXPECT_EQ(rect.GetLeft(), 5.0f);
200  EXPECT_EQ(rect.GetTop(), max);
201  EXPECT_EQ(rect.GetRight(), 25.0f);
202  EXPECT_EQ(rect.GetBottom(), inf);
203  EXPECT_EQ(rect.GetX(), 5.0f);
204  EXPECT_EQ(rect.GetY(), max);
205  EXPECT_EQ(rect.GetWidth(), 20.0f);
206  EXPECT_EQ(rect.GetHeight(), inf);
207  EXPECT_FALSE(rect.IsEmpty());
208  EXPECT_FALSE(rect.IsFinite());
209  }
210 
211  {
212  Rect rect = Rect::MakeXYWH(5.0, 10.0f, min, 15.0f);
213 
214  EXPECT_EQ(rect.GetLeft(), 5.0f);
215  EXPECT_EQ(rect.GetTop(), 10.0f);
216  EXPECT_EQ(rect.GetRight(), min);
217  EXPECT_EQ(rect.GetBottom(), 25.0f);
218  EXPECT_EQ(rect.GetX(), 5.0f);
219  EXPECT_EQ(rect.GetY(), 10.0f);
220  EXPECT_EQ(rect.GetWidth(), min);
221  EXPECT_EQ(rect.GetHeight(), 15.0f);
222  EXPECT_TRUE(rect.IsEmpty());
223  EXPECT_TRUE(rect.IsFinite());
224  }
225 
226  {
227  Rect rect = Rect::MakeXYWH(min, 10.0f, min, 15.0f);
228 
229  EXPECT_EQ(rect.GetLeft(), min);
230  EXPECT_EQ(rect.GetTop(), 10.0f);
231  EXPECT_EQ(rect.GetRight(), -inf);
232  EXPECT_EQ(rect.GetBottom(), 25.0f);
233  EXPECT_EQ(rect.GetX(), min);
234  EXPECT_EQ(rect.GetY(), 10.0f);
235  EXPECT_EQ(rect.GetWidth(), -inf);
236  EXPECT_EQ(rect.GetHeight(), 15.0f);
237  EXPECT_TRUE(rect.IsEmpty());
238  EXPECT_FALSE(rect.IsFinite());
239  }
240 
241  {
242  Rect rect = Rect::MakeXYWH(5.0f, 10.0f, 20.0f, min);
243 
244  EXPECT_EQ(rect.GetLeft(), 5.0f);
245  EXPECT_EQ(rect.GetTop(), 10.0f);
246  EXPECT_EQ(rect.GetRight(), 25.0f);
247  EXPECT_EQ(rect.GetBottom(), min);
248  EXPECT_EQ(rect.GetX(), 5.0f);
249  EXPECT_EQ(rect.GetY(), 10.0f);
250  EXPECT_EQ(rect.GetWidth(), 20.0f);
251  EXPECT_EQ(rect.GetHeight(), min);
252  EXPECT_TRUE(rect.IsEmpty());
253  EXPECT_TRUE(rect.IsFinite());
254  }
255 
256  {
257  Rect rect = Rect::MakeXYWH(5.0f, min, 20.0f, min);
258 
259  EXPECT_EQ(rect.GetLeft(), 5.0f);
260  EXPECT_EQ(rect.GetTop(), min);
261  EXPECT_EQ(rect.GetRight(), 25.0f);
262  EXPECT_EQ(rect.GetBottom(), -inf);
263  EXPECT_EQ(rect.GetX(), 5.0f);
264  EXPECT_EQ(rect.GetY(), min);
265  EXPECT_EQ(rect.GetWidth(), 20.0f);
266  EXPECT_EQ(rect.GetHeight(), -inf);
267  EXPECT_TRUE(rect.IsEmpty());
268  EXPECT_FALSE(rect.IsFinite());
269  }
270 }
271 
272 TEST(RectTest, IRectOverflowXYWH) {
273  auto min = std::numeric_limits<int64_t>::min();
274  auto max = std::numeric_limits<int64_t>::max();
275 
276  // 4 cases
277  // x near max, positive w takes it past max
278  // x near min, negative w takes it below min
279  // y near max, positive h takes it past max
280  // y near min, negative h takes it below min
281 
282  {
283  IRect rect = IRect::MakeXYWH(max - 5, 10, 10, 16);
284 
285  EXPECT_EQ(rect.GetLeft(), max - 5);
286  EXPECT_EQ(rect.GetTop(), 10);
287  EXPECT_EQ(rect.GetRight(), max);
288  EXPECT_EQ(rect.GetBottom(), 26);
289  EXPECT_EQ(rect.GetX(), max - 5);
290  EXPECT_EQ(rect.GetY(), 10);
291  EXPECT_EQ(rect.GetWidth(), 5);
292  EXPECT_EQ(rect.GetHeight(), 16);
293  EXPECT_FALSE(rect.IsEmpty());
294  }
295 
296  {
297  IRect rect = IRect::MakeXYWH(min + 5, 10, -10, 16);
298 
299  EXPECT_EQ(rect.GetLeft(), min + 5);
300  EXPECT_EQ(rect.GetTop(), 10);
301  EXPECT_EQ(rect.GetRight(), min);
302  EXPECT_EQ(rect.GetBottom(), 26);
303  EXPECT_EQ(rect.GetX(), min + 5);
304  EXPECT_EQ(rect.GetY(), 10);
305  EXPECT_EQ(rect.GetWidth(), -5);
306  EXPECT_EQ(rect.GetHeight(), 16);
307  EXPECT_TRUE(rect.IsEmpty());
308  }
309 
310  {
311  IRect rect = IRect::MakeXYWH(5, max - 10, 10, 16);
312 
313  EXPECT_EQ(rect.GetLeft(), 5);
314  EXPECT_EQ(rect.GetTop(), max - 10);
315  EXPECT_EQ(rect.GetRight(), 15);
316  EXPECT_EQ(rect.GetBottom(), max);
317  EXPECT_EQ(rect.GetX(), 5);
318  EXPECT_EQ(rect.GetY(), max - 10);
319  EXPECT_EQ(rect.GetWidth(), 10);
320  EXPECT_EQ(rect.GetHeight(), 10);
321  EXPECT_FALSE(rect.IsEmpty());
322  }
323 
324  {
325  IRect rect = IRect::MakeXYWH(5, min + 10, 10, -16);
326 
327  EXPECT_EQ(rect.GetLeft(), 5);
328  EXPECT_EQ(rect.GetTop(), min + 10);
329  EXPECT_EQ(rect.GetRight(), 15);
330  EXPECT_EQ(rect.GetBottom(), min);
331  EXPECT_EQ(rect.GetX(), 5);
332  EXPECT_EQ(rect.GetY(), min + 10);
333  EXPECT_EQ(rect.GetWidth(), 10);
334  EXPECT_EQ(rect.GetHeight(), -10);
335  EXPECT_TRUE(rect.IsEmpty());
336  }
337 }
338 
339 TEST(RectTest, RectOverflowLTRB) {
340  auto min = std::numeric_limits<Scalar>::lowest();
341  auto max = std::numeric_limits<Scalar>::max();
342  auto inf = std::numeric_limits<Scalar>::infinity();
343 
344  // 8 cases:
345  // finite negative X, max W
346  // ~min X, ~max W
347  // finite negative Y, max H
348  // ~min Y, ~max H
349  // finite positive X, min W
350  // ~min X, ~min W
351  // finite positive Y, min H
352  // ~min Y, ~min H
353 
354  // a small finite value subtracted from a max value will remain max
355  // a very large finite value (like min) subtracted from max will go to inf
356 
357  {
358  Rect rect = Rect::MakeLTRB(-5.0f, 10.0f, max, 25.0f);
359 
360  EXPECT_EQ(rect.GetLeft(), -5.0f);
361  EXPECT_EQ(rect.GetTop(), 10.0f);
362  EXPECT_EQ(rect.GetRight(), max);
363  EXPECT_EQ(rect.GetBottom(), 25.0f);
364  EXPECT_EQ(rect.GetX(), -5.0f);
365  EXPECT_EQ(rect.GetY(), 10.0f);
366  EXPECT_EQ(rect.GetWidth(), max);
367  EXPECT_EQ(rect.GetHeight(), 15.0f);
368  EXPECT_FALSE(rect.IsEmpty());
369  EXPECT_TRUE(rect.IsFinite());
370  }
371 
372  {
373  Rect rect = Rect::MakeLTRB(min + 5.0f, 10.0f, max - 5.0f, 25.0f);
374 
375  EXPECT_EQ(rect.GetLeft(), min + 5.0f);
376  EXPECT_EQ(rect.GetTop(), 10.0f);
377  EXPECT_EQ(rect.GetRight(), max - 5.0f);
378  EXPECT_EQ(rect.GetBottom(), 25.0f);
379  EXPECT_EQ(rect.GetX(), min + 5.0f);
380  EXPECT_EQ(rect.GetY(), 10.0f);
381  EXPECT_EQ(rect.GetWidth(), inf);
382  EXPECT_EQ(rect.GetHeight(), 15.0f);
383  EXPECT_FALSE(rect.IsEmpty());
384  EXPECT_TRUE(rect.IsFinite());
385  }
386 
387  {
388  Rect rect = Rect::MakeLTRB(5.0f, -10.0f, 20.0f, max);
389 
390  EXPECT_EQ(rect.GetLeft(), 5.0f);
391  EXPECT_EQ(rect.GetTop(), -10.0f);
392  EXPECT_EQ(rect.GetRight(), 20.0f);
393  EXPECT_EQ(rect.GetBottom(), max);
394  EXPECT_EQ(rect.GetX(), 5.0f);
395  EXPECT_EQ(rect.GetY(), -10.0f);
396  EXPECT_EQ(rect.GetWidth(), 15.0f);
397  EXPECT_EQ(rect.GetHeight(), max);
398  EXPECT_FALSE(rect.IsEmpty());
399  EXPECT_TRUE(rect.IsFinite());
400  }
401 
402  {
403  Rect rect = Rect::MakeLTRB(5.0f, min + 10.0f, 20.0f, max - 15.0f);
404 
405  EXPECT_EQ(rect.GetLeft(), 5.0f);
406  EXPECT_EQ(rect.GetTop(), min + 10.0f);
407  EXPECT_EQ(rect.GetRight(), 20.0f);
408  EXPECT_EQ(rect.GetBottom(), max - 15.0f);
409  EXPECT_EQ(rect.GetX(), 5.0f);
410  EXPECT_EQ(rect.GetY(), min + 10.0f);
411  EXPECT_EQ(rect.GetWidth(), 15.0f);
412  EXPECT_EQ(rect.GetHeight(), inf);
413  EXPECT_FALSE(rect.IsEmpty());
414  EXPECT_TRUE(rect.IsFinite());
415  }
416 
417  {
418  Rect rect = Rect::MakeLTRB(5.0f, 10.0f, min, 25.0f);
419 
420  EXPECT_EQ(rect.GetLeft(), 5.0f);
421  EXPECT_EQ(rect.GetTop(), 10.0f);
422  EXPECT_EQ(rect.GetRight(), min);
423  EXPECT_EQ(rect.GetBottom(), 25.0f);
424  EXPECT_EQ(rect.GetX(), 5.0f);
425  EXPECT_EQ(rect.GetY(), 10.0f);
426  EXPECT_EQ(rect.GetWidth(), min);
427  EXPECT_EQ(rect.GetHeight(), 15.0f);
428  EXPECT_TRUE(rect.IsEmpty());
429  EXPECT_TRUE(rect.IsFinite());
430  }
431 
432  {
433  Rect rect = Rect::MakeLTRB(max - 5.0f, 10.0f, min + 10.0f, 25.0f);
434 
435  EXPECT_EQ(rect.GetLeft(), max - 5.0f);
436  EXPECT_EQ(rect.GetTop(), 10.0f);
437  EXPECT_EQ(rect.GetRight(), min + 10.0f);
438  EXPECT_EQ(rect.GetBottom(), 25.0f);
439  EXPECT_EQ(rect.GetX(), max - 5.0f);
440  EXPECT_EQ(rect.GetY(), 10.0f);
441  EXPECT_EQ(rect.GetWidth(), -inf);
442  EXPECT_EQ(rect.GetHeight(), 15.0f);
443  EXPECT_TRUE(rect.IsEmpty());
444  EXPECT_TRUE(rect.IsFinite());
445  }
446 
447  {
448  Rect rect = Rect::MakeLTRB(5.0f, 10.0f, 20.0f, min);
449 
450  EXPECT_EQ(rect.GetLeft(), 5.0f);
451  EXPECT_EQ(rect.GetTop(), 10.0f);
452  EXPECT_EQ(rect.GetRight(), 20.0f);
453  EXPECT_EQ(rect.GetBottom(), min);
454  EXPECT_EQ(rect.GetX(), 5.0f);
455  EXPECT_EQ(rect.GetY(), 10.0f);
456  EXPECT_EQ(rect.GetWidth(), 15.0f);
457  EXPECT_EQ(rect.GetHeight(), min);
458  EXPECT_TRUE(rect.IsEmpty());
459  EXPECT_TRUE(rect.IsFinite());
460  }
461 
462  {
463  Rect rect = Rect::MakeLTRB(5.0f, max - 5.0f, 20.0f, min + 10.0f);
464 
465  EXPECT_EQ(rect.GetLeft(), 5.0f);
466  EXPECT_EQ(rect.GetTop(), max - 5.0f);
467  EXPECT_EQ(rect.GetRight(), 20.0f);
468  EXPECT_EQ(rect.GetBottom(), min + 10.0f);
469  EXPECT_EQ(rect.GetX(), 5.0f);
470  EXPECT_EQ(rect.GetY(), max - 5.0f);
471  EXPECT_EQ(rect.GetWidth(), 15.0f);
472  EXPECT_EQ(rect.GetHeight(), -inf);
473  EXPECT_TRUE(rect.IsEmpty());
474  EXPECT_TRUE(rect.IsFinite());
475  }
476 }
477 
478 TEST(RectTest, IRectOverflowLTRB) {
479  auto min = std::numeric_limits<int64_t>::min();
480  auto max = std::numeric_limits<int64_t>::max();
481 
482  // 4 cases
483  // negative l, r near max takes width past max
484  // positive l, r near min takes width below min
485  // negative t, b near max takes width past max
486  // positive t, b near min takes width below min
487 
488  {
489  IRect rect = IRect::MakeLTRB(-10, 10, max - 5, 26);
490 
491  EXPECT_EQ(rect.GetLeft(), -10);
492  EXPECT_EQ(rect.GetTop(), 10);
493  EXPECT_EQ(rect.GetRight(), max - 5);
494  EXPECT_EQ(rect.GetBottom(), 26);
495  EXPECT_EQ(rect.GetX(), -10);
496  EXPECT_EQ(rect.GetY(), 10);
497  EXPECT_EQ(rect.GetWidth(), max);
498  EXPECT_EQ(rect.GetHeight(), 16);
499  EXPECT_FALSE(rect.IsEmpty());
500  }
501 
502  {
503  IRect rect = IRect::MakeLTRB(10, 10, min + 5, 26);
504 
505  EXPECT_EQ(rect.GetLeft(), 10);
506  EXPECT_EQ(rect.GetTop(), 10);
507  EXPECT_EQ(rect.GetRight(), min + 5);
508  EXPECT_EQ(rect.GetBottom(), 26);
509  EXPECT_EQ(rect.GetX(), 10);
510  EXPECT_EQ(rect.GetY(), 10);
511  EXPECT_EQ(rect.GetWidth(), min);
512  EXPECT_EQ(rect.GetHeight(), 16);
513  EXPECT_TRUE(rect.IsEmpty());
514  }
515 
516  {
517  IRect rect = IRect::MakeLTRB(5, -10, 15, max - 5);
518 
519  EXPECT_EQ(rect.GetLeft(), 5);
520  EXPECT_EQ(rect.GetTop(), -10);
521  EXPECT_EQ(rect.GetRight(), 15);
522  EXPECT_EQ(rect.GetBottom(), max - 5);
523  EXPECT_EQ(rect.GetX(), 5);
524  EXPECT_EQ(rect.GetY(), -10);
525  EXPECT_EQ(rect.GetWidth(), 10);
526  EXPECT_EQ(rect.GetHeight(), max);
527  EXPECT_FALSE(rect.IsEmpty());
528  }
529 
530  {
531  IRect rect = IRect::MakeLTRB(5, 10, 15, min + 5);
532 
533  EXPECT_EQ(rect.GetLeft(), 5);
534  EXPECT_EQ(rect.GetTop(), 10);
535  EXPECT_EQ(rect.GetRight(), 15);
536  EXPECT_EQ(rect.GetBottom(), min + 5);
537  EXPECT_EQ(rect.GetX(), 5);
538  EXPECT_EQ(rect.GetY(), 10);
539  EXPECT_EQ(rect.GetWidth(), 10);
540  EXPECT_EQ(rect.GetHeight(), min);
541  EXPECT_TRUE(rect.IsEmpty());
542  }
543 }
544 
545 TEST(RectTest, RectMakeSize) {
546  {
547  Size s(100, 200);
548  Rect r = Rect::MakeSize(s);
549  Rect expected = Rect::MakeLTRB(0, 0, 100, 200);
550  EXPECT_RECT_NEAR(r, expected);
551  }
552 
553  {
554  ISize s(100, 200);
555  Rect r = Rect::MakeSize(s);
556  Rect expected = Rect::MakeLTRB(0, 0, 100, 200);
557  EXPECT_RECT_NEAR(r, expected);
558  }
559 
560  {
561  Size s(100, 200);
562  IRect r = IRect::MakeSize(s);
563  IRect expected = IRect::MakeLTRB(0, 0, 100, 200);
564  EXPECT_EQ(r, expected);
565  }
566 
567  {
568  ISize s(100, 200);
569  IRect r = IRect::MakeSize(s);
570  IRect expected = IRect::MakeLTRB(0, 0, 100, 200);
571  EXPECT_EQ(r, expected);
572  }
573 }
574 
575 TEST(RectTest, RectMakeMaximum) {
576  Rect rect = Rect::MakeMaximum();
577  auto inf = std::numeric_limits<Scalar>::infinity();
578  auto min = std::numeric_limits<Scalar>::lowest();
579  auto max = std::numeric_limits<Scalar>::max();
580 
581  EXPECT_EQ(rect.GetLeft(), min);
582  EXPECT_EQ(rect.GetTop(), min);
583  EXPECT_EQ(rect.GetRight(), max);
584  EXPECT_EQ(rect.GetBottom(), max);
585  EXPECT_EQ(rect.GetX(), min);
586  EXPECT_EQ(rect.GetY(), min);
587  EXPECT_EQ(rect.GetWidth(), inf);
588  EXPECT_EQ(rect.GetHeight(), inf);
589  EXPECT_FALSE(rect.IsEmpty());
590  EXPECT_TRUE(rect.IsFinite());
591 }
592 
593 TEST(RectTest, IRectMakeMaximum) {
594  IRect rect = IRect::MakeMaximum();
595  auto min = std::numeric_limits<int64_t>::min();
596  auto max = std::numeric_limits<int64_t>::max();
597 
598  EXPECT_EQ(rect.GetLeft(), min);
599  EXPECT_EQ(rect.GetTop(), min);
600  EXPECT_EQ(rect.GetRight(), max);
601  EXPECT_EQ(rect.GetBottom(), max);
602  EXPECT_EQ(rect.GetX(), min);
603  EXPECT_EQ(rect.GetY(), min);
604  EXPECT_EQ(rect.GetWidth(), max);
605  EXPECT_EQ(rect.GetHeight(), max);
606  EXPECT_FALSE(rect.IsEmpty());
607 }
608 
609 TEST(RectTest, RectFromRect) {
610  EXPECT_EQ(Rect(Rect::MakeXYWH(2, 3, 7, 15)),
611  Rect::MakeXYWH(2.0, 3.0, 7.0, 15.0));
612  EXPECT_EQ(Rect(Rect::MakeLTRB(2, 3, 7, 15)),
613  Rect::MakeLTRB(2.0, 3.0, 7.0, 15.0));
614 }
615 
616 TEST(RectTest, IRectFromIRect) {
617  EXPECT_EQ(IRect(IRect::MakeXYWH(2, 3, 7, 15)), //
618  IRect::MakeXYWH(2, 3, 7, 15));
619  EXPECT_EQ(IRect(IRect::MakeLTRB(2, 3, 7, 15)), //
620  IRect::MakeLTRB(2, 3, 7, 15));
621 }
622 
623 TEST(RectTest, RectCopy) {
624  // Using fractional-power-of-2 friendly values for equality tests
625  Rect rect = Rect::MakeLTRB(5.125f, 10.25f, 20.625f, 25.375f);
626  Rect copy = rect;
627 
628  EXPECT_EQ(rect, copy);
629  EXPECT_EQ(copy.GetLeft(), 5.125f);
630  EXPECT_EQ(copy.GetTop(), 10.25f);
631  EXPECT_EQ(copy.GetRight(), 20.625f);
632  EXPECT_EQ(copy.GetBottom(), 25.375f);
633  EXPECT_EQ(copy.GetX(), 5.125f);
634  EXPECT_EQ(copy.GetY(), 10.25f);
635  EXPECT_EQ(copy.GetWidth(), 15.5f);
636  EXPECT_EQ(copy.GetHeight(), 15.125f);
637  EXPECT_FALSE(copy.IsEmpty());
638  EXPECT_TRUE(copy.IsFinite());
639 }
640 
641 TEST(RectTest, IRectCopy) {
642  IRect rect = IRect::MakeLTRB(5, 10, 20, 25);
643  IRect copy = rect;
644 
645  EXPECT_EQ(rect, copy);
646  EXPECT_EQ(copy.GetLeft(), 5);
647  EXPECT_EQ(copy.GetTop(), 10);
648  EXPECT_EQ(copy.GetRight(), 20);
649  EXPECT_EQ(copy.GetBottom(), 25);
650  EXPECT_EQ(copy.GetX(), 5);
651  EXPECT_EQ(copy.GetY(), 10);
652  EXPECT_EQ(copy.GetWidth(), 15);
653  EXPECT_EQ(copy.GetHeight(), 15);
654  EXPECT_FALSE(copy.IsEmpty());
655 }
656 
657 TEST(RectTest, RectOriginSizeXYWHGetters) {
658  {
659  Rect r = Rect::MakeOriginSize({10, 20}, {50, 40});
660  EXPECT_EQ(r.GetOrigin(), Point(10, 20));
661  EXPECT_EQ(r.GetSize(), Size(50, 40));
662  EXPECT_EQ(r.GetX(), 10);
663  EXPECT_EQ(r.GetY(), 20);
664  EXPECT_EQ(r.GetWidth(), 50);
665  EXPECT_EQ(r.GetHeight(), 40);
666  auto expected_array = std::array<Scalar, 4>{10, 20, 50, 40};
667  EXPECT_EQ(r.GetXYWH(), expected_array);
668  }
669 
670  {
671  Rect r = Rect::MakeLTRB(10, 20, 50, 40);
672  EXPECT_EQ(r.GetOrigin(), Point(10, 20));
673  EXPECT_EQ(r.GetSize(), Size(40, 20));
674  EXPECT_EQ(r.GetX(), 10);
675  EXPECT_EQ(r.GetY(), 20);
676  EXPECT_EQ(r.GetWidth(), 40);
677  EXPECT_EQ(r.GetHeight(), 20);
678  auto expected_array = std::array<Scalar, 4>{10, 20, 40, 20};
679  EXPECT_EQ(r.GetXYWH(), expected_array);
680  }
681 }
682 
683 TEST(RectTest, IRectOriginSizeXYWHGetters) {
684  {
685  IRect r = IRect::MakeOriginSize({10, 20}, {50, 40});
686  EXPECT_EQ(r.GetOrigin(), IPoint(10, 20));
687  EXPECT_EQ(r.GetSize(), ISize(50, 40));
688  EXPECT_EQ(r.GetX(), 10);
689  EXPECT_EQ(r.GetY(), 20);
690  EXPECT_EQ(r.GetWidth(), 50);
691  EXPECT_EQ(r.GetHeight(), 40);
692  auto expected_array = std::array<int64_t, 4>{10, 20, 50, 40};
693  EXPECT_EQ(r.GetXYWH(), expected_array);
694  }
695 
696  {
697  IRect r = IRect::MakeLTRB(10, 20, 50, 40);
698  EXPECT_EQ(r.GetOrigin(), IPoint(10, 20));
699  EXPECT_EQ(r.GetSize(), ISize(40, 20));
700  EXPECT_EQ(r.GetX(), 10);
701  EXPECT_EQ(r.GetY(), 20);
702  EXPECT_EQ(r.GetWidth(), 40);
703  EXPECT_EQ(r.GetHeight(), 20);
704  auto expected_array = std::array<int64_t, 4>{10, 20, 40, 20};
705  EXPECT_EQ(r.GetXYWH(), expected_array);
706  }
707 }
708 
709 TEST(RectTest, RectRoundOutEmpty) {
710  Rect rect;
711 
712  EXPECT_EQ(Rect::RoundOut(rect), Rect());
713 
714  EXPECT_EQ(IRect::RoundOut(rect), IRect());
715 }
716 
717 TEST(RectTest, RectRoundOutSimple) {
718  Rect rect = Rect::MakeLTRB(5.125f, 10.75f, 20.625f, 25.375f);
719 
720  EXPECT_EQ(Rect::RoundOut(rect), Rect::MakeLTRB(5.0f, 10.0f, 21.0f, 26.0f));
721 
722  EXPECT_EQ(IRect::RoundOut(rect), IRect::MakeLTRB(5, 10, 21, 26));
723 }
724 
725 TEST(RectTest, RectRoundOutToIRectHuge) {
726  auto test = [](int corners) {
727  EXPECT_TRUE(corners >= 0 && corners <= 0xf);
728  Scalar l, t, r, b;
729  int64_t il, it, ir, ib;
730  l = il = 50;
731  t = it = 50;
732  r = ir = 80;
733  b = ib = 80;
734  if ((corners & (1 << 0)) != 0) {
735  l = -1E20;
736  il = std::numeric_limits<int64_t>::min();
737  }
738  if ((corners & (1 << 1)) != 0) {
739  t = -1E20;
740  it = std::numeric_limits<int64_t>::min();
741  }
742  if ((corners & (1 << 2)) != 0) {
743  r = +1E20;
744  ir = std::numeric_limits<int64_t>::max();
745  }
746  if ((corners & (1 << 3)) != 0) {
747  b = +1E20;
748  ib = std::numeric_limits<int64_t>::max();
749  }
750 
751  Rect rect = Rect::MakeLTRB(l, t, r, b);
752  IRect irect = IRect::RoundOut(rect);
753  EXPECT_EQ(irect.GetLeft(), il) << corners;
754  EXPECT_EQ(irect.GetTop(), it) << corners;
755  EXPECT_EQ(irect.GetRight(), ir) << corners;
756  EXPECT_EQ(irect.GetBottom(), ib) << corners;
757  };
758 
759  for (int corners = 0; corners <= 15; corners++) {
760  test(corners);
761  }
762 }
763 
764 TEST(RectTest, RectDoesNotIntersectEmpty) {
765  Rect rect = Rect::MakeLTRB(50, 50, 100, 100);
766 
767  auto test = [&rect](Scalar l, Scalar t, Scalar r, Scalar b,
768  const std::string& label) {
769  EXPECT_FALSE(rect.IntersectsWithRect(Rect::MakeLTRB(l, b, r, t)))
770  << label << " with Top/Bottom swapped";
771  EXPECT_FALSE(rect.IntersectsWithRect(Rect::MakeLTRB(r, b, l, t)))
772  << label << " with Left/Right swapped";
773  EXPECT_FALSE(rect.IntersectsWithRect(Rect::MakeLTRB(r, t, l, b)))
774  << label << " with all sides swapped";
775  };
776 
777  test(20, 20, 30, 30, "Above and Left");
778  test(70, 20, 80, 30, "Above");
779  test(120, 20, 130, 30, "Above and Right");
780  test(120, 70, 130, 80, "Right");
781  test(120, 120, 130, 130, "Below and Right");
782  test(70, 120, 80, 130, "Below");
783  test(20, 120, 30, 130, "Below and Left");
784  test(20, 70, 30, 80, "Left");
785 
786  test(70, 70, 80, 80, "Inside");
787 
788  test(40, 70, 60, 80, "Straddling Left");
789  test(70, 40, 80, 60, "Straddling Top");
790  test(90, 70, 110, 80, "Straddling Right");
791  test(70, 90, 80, 110, "Straddling Bottom");
792 }
793 
794 TEST(RectTest, IRectDoesNotIntersectEmpty) {
795  IRect rect = IRect::MakeLTRB(50, 50, 100, 100);
796 
797  auto test = [&rect](int64_t l, int64_t t, int64_t r, int64_t b,
798  const std::string& label) {
799  EXPECT_FALSE(rect.IntersectsWithRect(IRect::MakeLTRB(l, b, r, t)))
800  << label << " with Top/Bottom swapped";
801  EXPECT_FALSE(rect.IntersectsWithRect(IRect::MakeLTRB(r, b, l, t)))
802  << label << " with Left/Right swapped";
803  EXPECT_FALSE(rect.IntersectsWithRect(IRect::MakeLTRB(r, t, l, b)))
804  << label << " with all sides swapped";
805  };
806 
807  test(20, 20, 30, 30, "Above and Left");
808  test(70, 20, 80, 30, "Above");
809  test(120, 20, 130, 30, "Above and Right");
810  test(120, 70, 130, 80, "Right");
811  test(120, 120, 130, 130, "Below and Right");
812  test(70, 120, 80, 130, "Below");
813  test(20, 120, 30, 130, "Below and Left");
814  test(20, 70, 30, 80, "Left");
815 
816  test(70, 70, 80, 80, "Inside");
817 
818  test(40, 70, 60, 80, "Straddling Left");
819  test(70, 40, 80, 60, "Straddling Top");
820  test(90, 70, 110, 80, "Straddling Right");
821  test(70, 90, 80, 110, "Straddling Bottom");
822 }
823 
824 TEST(RectTest, EmptyRectDoesNotIntersect) {
825  Rect rect = Rect::MakeLTRB(50, 50, 100, 100);
826 
827  auto test = [&rect](Scalar l, Scalar t, Scalar r, Scalar b,
828  const std::string& label) {
829  EXPECT_FALSE(Rect::MakeLTRB(l, b, r, t).IntersectsWithRect(rect))
830  << label << " with Top/Bottom swapped";
831  EXPECT_FALSE(Rect::MakeLTRB(r, b, l, t).IntersectsWithRect(rect))
832  << label << " with Left/Right swapped";
833  EXPECT_FALSE(Rect::MakeLTRB(r, t, l, b).IntersectsWithRect(rect))
834  << label << " with all sides swapped";
835  };
836 
837  test(20, 20, 30, 30, "Above and Left");
838  test(70, 20, 80, 30, "Above");
839  test(120, 20, 130, 30, "Above and Right");
840  test(120, 70, 130, 80, "Right");
841  test(120, 120, 130, 130, "Below and Right");
842  test(70, 120, 80, 130, "Below");
843  test(20, 120, 30, 130, "Below and Left");
844  test(20, 70, 30, 80, "Left");
845 
846  test(70, 70, 80, 80, "Inside");
847 
848  test(40, 70, 60, 80, "Straddling Left");
849  test(70, 40, 80, 60, "Straddling Top");
850  test(90, 70, 110, 80, "Straddling Right");
851  test(70, 90, 80, 110, "Straddling Bottom");
852 }
853 
854 TEST(RectTest, EmptyIRectDoesNotIntersect) {
855  IRect rect = IRect::MakeLTRB(50, 50, 100, 100);
856 
857  auto test = [&rect](int64_t l, int64_t t, int64_t r, int64_t b,
858  const std::string& label) {
859  EXPECT_FALSE(IRect::MakeLTRB(l, b, r, t).IntersectsWithRect(rect))
860  << label << " with Top/Bottom swapped";
861  EXPECT_FALSE(IRect::MakeLTRB(r, b, l, t).IntersectsWithRect(rect))
862  << label << " with Left/Right swapped";
863  EXPECT_FALSE(IRect::MakeLTRB(r, t, l, b).IntersectsWithRect(rect))
864  << label << " with all sides swapped";
865  };
866 
867  test(20, 20, 30, 30, "Above and Left");
868  test(70, 20, 80, 30, "Above");
869  test(120, 20, 130, 30, "Above and Right");
870  test(120, 70, 130, 80, "Right");
871  test(120, 120, 130, 130, "Below and Right");
872  test(70, 120, 80, 130, "Below");
873  test(20, 120, 30, 130, "Below and Left");
874  test(20, 70, 30, 80, "Left");
875 
876  test(70, 70, 80, 80, "Inside");
877 
878  test(40, 70, 60, 80, "Straddling Left");
879  test(70, 40, 80, 60, "Straddling Top");
880  test(90, 70, 110, 80, "Straddling Right");
881  test(70, 90, 80, 110, "Straddling Bottom");
882 }
883 
884 TEST(RectTest, RectScale) {
885  auto test1 = [](Rect rect, Scalar scale) {
886  Rect expected = Rect::MakeXYWH(rect.GetX() * scale, //
887  rect.GetY() * scale, //
888  rect.GetWidth() * scale, //
889  rect.GetHeight() * scale);
890 
891  EXPECT_RECT_NEAR(rect.Scale(scale), expected) //
892  << rect << " * " << scale;
893  EXPECT_RECT_NEAR(rect.Scale(scale, scale), expected) //
894  << rect << " * " << scale;
895  EXPECT_RECT_NEAR(rect.Scale(Point(scale, scale)), expected) //
896  << rect << " * " << scale;
897  EXPECT_RECT_NEAR(rect.Scale(Size(scale, scale)), expected) //
898  << rect << " * " << scale;
899  };
900 
901  auto test2 = [&test1](Rect rect, Scalar scale_x, Scalar scale_y) {
902  Rect expected = Rect::MakeXYWH(rect.GetX() * scale_x, //
903  rect.GetY() * scale_y, //
904  rect.GetWidth() * scale_x, //
905  rect.GetHeight() * scale_y);
906 
907  EXPECT_RECT_NEAR(rect.Scale(scale_x, scale_y), expected) //
908  << rect << " * " << scale_x << ", " << scale_y;
909  EXPECT_RECT_NEAR(rect.Scale(Point(scale_x, scale_y)), expected) //
910  << rect << " * " << scale_x << ", " << scale_y;
911  EXPECT_RECT_NEAR(rect.Scale(Size(scale_x, scale_y)), expected) //
912  << rect << " * " << scale_x << ", " << scale_y;
913 
914  test1(rect, scale_x);
915  test1(rect, scale_y);
916  };
917 
918  test2(Rect::MakeLTRB(10, 15, 100, 150), 1.0, 0.0);
919  test2(Rect::MakeLTRB(10, 15, 100, 150), 0.0, 1.0);
920  test2(Rect::MakeLTRB(10, 15, 100, 150), 0.0, 0.0);
921  test2(Rect::MakeLTRB(10, 15, 100, 150), 2.5, 3.5);
922  test2(Rect::MakeLTRB(10, 15, 100, 150), 3.5, 2.5);
923  test2(Rect::MakeLTRB(10, 15, -100, 150), 2.5, 3.5);
924  test2(Rect::MakeLTRB(10, 15, 100, -150), 2.5, 3.5);
925  test2(Rect::MakeLTRB(10, 15, 100, 150), -2.5, 3.5);
926  test2(Rect::MakeLTRB(10, 15, 100, 150), 2.5, -3.5);
927 }
928 
929 TEST(RectTest, IRectScale) {
930  auto test1 = [](IRect rect, int64_t scale) {
931  IRect expected = IRect::MakeXYWH(rect.GetX() * scale, //
932  rect.GetY() * scale, //
933  rect.GetWidth() * scale, //
934  rect.GetHeight() * scale);
935 
936  EXPECT_EQ(rect.Scale(scale), expected) //
937  << rect << " * " << scale;
938  EXPECT_EQ(rect.Scale(scale, scale), expected) //
939  << rect << " * " << scale;
940  EXPECT_EQ(rect.Scale(IPoint(scale, scale)), expected) //
941  << rect << " * " << scale;
942  EXPECT_EQ(rect.Scale(ISize(scale, scale)), expected) //
943  << rect << " * " << scale;
944  };
945 
946  auto test2 = [&test1](IRect rect, int64_t scale_x, int64_t scale_y) {
947  IRect expected = IRect::MakeXYWH(rect.GetX() * scale_x, //
948  rect.GetY() * scale_y, //
949  rect.GetWidth() * scale_x, //
950  rect.GetHeight() * scale_y);
951 
952  EXPECT_EQ(rect.Scale(scale_x, scale_y), expected) //
953  << rect << " * " << scale_x << ", " << scale_y;
954  EXPECT_EQ(rect.Scale(IPoint(scale_x, scale_y)), expected) //
955  << rect << " * " << scale_x << ", " << scale_y;
956  EXPECT_EQ(rect.Scale(ISize(scale_x, scale_y)), expected) //
957  << rect << " * " << scale_x << ", " << scale_y;
958 
959  test1(rect, scale_x);
960  test1(rect, scale_y);
961  };
962 
963  test2(IRect::MakeLTRB(10, 15, 100, 150), 2, 3);
964  test2(IRect::MakeLTRB(10, 15, 100, 150), 3, 2);
965  test2(IRect::MakeLTRB(10, 15, -100, 150), 2, 3);
966  test2(IRect::MakeLTRB(10, 15, 100, -150), 2, 3);
967  test2(IRect::MakeLTRB(10, 15, 100, 150), -2, 3);
968  test2(IRect::MakeLTRB(10, 15, 100, 150), 2, -3);
969 }
970 
971 TEST(RectTest, RectArea) {
972  EXPECT_EQ(Rect::MakeXYWH(0, 0, 100, 200).Area(), 20000);
973  EXPECT_EQ(Rect::MakeXYWH(10, 20, 100, 200).Area(), 20000);
974  EXPECT_EQ(Rect::MakeXYWH(0, 0, 200, 100).Area(), 20000);
975  EXPECT_EQ(Rect::MakeXYWH(10, 20, 200, 100).Area(), 20000);
976  EXPECT_EQ(Rect::MakeXYWH(0, 0, 100, 100).Area(), 10000);
977  EXPECT_EQ(Rect::MakeXYWH(10, 20, 100, 100).Area(), 10000);
978 }
979 
980 TEST(RectTest, IRectArea) {
981  EXPECT_EQ(IRect::MakeXYWH(0, 0, 100, 200).Area(), 20000);
982  EXPECT_EQ(IRect::MakeXYWH(10, 20, 100, 200).Area(), 20000);
983  EXPECT_EQ(IRect::MakeXYWH(0, 0, 200, 100).Area(), 20000);
984  EXPECT_EQ(IRect::MakeXYWH(10, 20, 200, 100).Area(), 20000);
985  EXPECT_EQ(IRect::MakeXYWH(0, 0, 100, 100).Area(), 10000);
986  EXPECT_EQ(IRect::MakeXYWH(10, 20, 100, 100).Area(), 10000);
987 }
988 
989 TEST(RectTest, RectGetNormalizingTransform) {
990  {
991  // Checks for expected matrix values
992 
993  auto r = Rect::MakeXYWH(100, 200, 200, 400);
994 
995  EXPECT_EQ(r.GetNormalizingTransform(),
996  Matrix::MakeScale({0.005, 0.0025, 1.0}) *
997  Matrix::MakeTranslation({-100, -200}));
998  }
999 
1000  {
1001  // Checks for expected transform of points relative to the rect
1002 
1003  auto r = Rect::MakeLTRB(300, 500, 400, 700);
1004  auto m = r.GetNormalizingTransform();
1005 
1006  // The 4 corners of the rect => (0, 0) to (1, 1)
1007  EXPECT_EQ(m * Point(300, 500), Point(0, 0));
1008  EXPECT_EQ(m * Point(400, 500), Point(1, 0));
1009  EXPECT_EQ(m * Point(400, 700), Point(1, 1));
1010  EXPECT_EQ(m * Point(300, 700), Point(0, 1));
1011 
1012  // The center => (0.5, 0.5)
1013  EXPECT_EQ(m * Point(350, 600), Point(0.5, 0.5));
1014 
1015  // Outside the 4 corners => (-1, -1) to (2, 2)
1016  EXPECT_EQ(m * Point(200, 300), Point(-1, -1));
1017  EXPECT_EQ(m * Point(500, 300), Point(2, -1));
1018  EXPECT_EQ(m * Point(500, 900), Point(2, 2));
1019  EXPECT_EQ(m * Point(200, 900), Point(-1, 2));
1020  }
1021 
1022  {
1023  // Checks for behavior with empty rects
1024 
1025  auto zero = Matrix::MakeScale({0.0, 0.0, 1.0});
1026 
1027  // Empty for width and/or height == 0
1028  EXPECT_EQ(Rect::MakeXYWH(10, 10, 0, 10).GetNormalizingTransform(), zero);
1029  EXPECT_EQ(Rect::MakeXYWH(10, 10, 10, 0).GetNormalizingTransform(), zero);
1030  EXPECT_EQ(Rect::MakeXYWH(10, 10, 0, 0).GetNormalizingTransform(), zero);
1031 
1032  // Empty for width and/or height < 0
1033  EXPECT_EQ(Rect::MakeXYWH(10, 10, -1, 10).GetNormalizingTransform(), zero);
1034  EXPECT_EQ(Rect::MakeXYWH(10, 10, 10, -1).GetNormalizingTransform(), zero);
1035  EXPECT_EQ(Rect::MakeXYWH(10, 10, -1, -1).GetNormalizingTransform(), zero);
1036  }
1037 
1038  {
1039  // Checks for behavior with non-finite rects
1040 
1041  auto z = Matrix::MakeScale({0.0, 0.0, 1.0});
1042  auto nan = std::numeric_limits<Scalar>::quiet_NaN();
1043  auto inf = std::numeric_limits<Scalar>::infinity();
1044 
1045  // Non-finite for width and/or height == nan
1046  EXPECT_EQ(Rect::MakeXYWH(10, 10, nan, 10).GetNormalizingTransform(), z);
1047  EXPECT_EQ(Rect::MakeXYWH(10, 10, 10, nan).GetNormalizingTransform(), z);
1048  EXPECT_EQ(Rect::MakeXYWH(10, 10, nan, nan).GetNormalizingTransform(), z);
1049 
1050  // Non-finite for width and/or height == inf
1051  EXPECT_EQ(Rect::MakeXYWH(10, 10, inf, 10).GetNormalizingTransform(), z);
1052  EXPECT_EQ(Rect::MakeXYWH(10, 10, 10, inf).GetNormalizingTransform(), z);
1053  EXPECT_EQ(Rect::MakeXYWH(10, 10, inf, inf).GetNormalizingTransform(), z);
1054 
1055  // Non-finite for width and/or height == -inf
1056  EXPECT_EQ(Rect::MakeXYWH(10, 10, -inf, 10).GetNormalizingTransform(), z);
1057  EXPECT_EQ(Rect::MakeXYWH(10, 10, 10, -inf).GetNormalizingTransform(), z);
1058  EXPECT_EQ(Rect::MakeXYWH(10, 10, -inf, -inf).GetNormalizingTransform(), z);
1059 
1060  // Non-finite for origin X and/or Y == nan
1061  EXPECT_EQ(Rect::MakeXYWH(nan, 10, 10, 10).GetNormalizingTransform(), z);
1062  EXPECT_EQ(Rect::MakeXYWH(10, nan, 10, 10).GetNormalizingTransform(), z);
1063  EXPECT_EQ(Rect::MakeXYWH(nan, nan, 10, 10).GetNormalizingTransform(), z);
1064 
1065  // Non-finite for origin X and/or Y == inf
1066  EXPECT_EQ(Rect::MakeXYWH(inf, 10, 10, 10).GetNormalizingTransform(), z);
1067  EXPECT_EQ(Rect::MakeXYWH(10, inf, 10, 10).GetNormalizingTransform(), z);
1068  EXPECT_EQ(Rect::MakeXYWH(inf, inf, 10, 10).GetNormalizingTransform(), z);
1069 
1070  // Non-finite for origin X and/or Y == -inf
1071  EXPECT_EQ(Rect::MakeXYWH(-inf, 10, 10, 10).GetNormalizingTransform(), z);
1072  EXPECT_EQ(Rect::MakeXYWH(10, -inf, 10, 10).GetNormalizingTransform(), z);
1073  EXPECT_EQ(Rect::MakeXYWH(-inf, -inf, 10, 10).GetNormalizingTransform(), z);
1074  }
1075 }
1076 
1077 TEST(RectTest, IRectGetNormalizingTransform) {
1078  {
1079  // Checks for expected matrix values
1080 
1081  auto r = IRect::MakeXYWH(100, 200, 200, 400);
1082 
1083  EXPECT_EQ(r.GetNormalizingTransform(),
1084  Matrix::MakeScale({0.005, 0.0025, 1.0}) *
1085  Matrix::MakeTranslation({-100, -200}));
1086  }
1087 
1088  {
1089  // Checks for expected transform of points relative to the rect
1090 
1091  auto r = IRect::MakeLTRB(300, 500, 400, 700);
1092  auto m = r.GetNormalizingTransform();
1093 
1094  // The 4 corners of the rect => (0, 0) to (1, 1)
1095  EXPECT_EQ(m * Point(300, 500), Point(0, 0));
1096  EXPECT_EQ(m * Point(400, 500), Point(1, 0));
1097  EXPECT_EQ(m * Point(400, 700), Point(1, 1));
1098  EXPECT_EQ(m * Point(300, 700), Point(0, 1));
1099 
1100  // The center => (0.5, 0.5)
1101  EXPECT_EQ(m * Point(350, 600), Point(0.5, 0.5));
1102 
1103  // Outside the 4 corners => (-1, -1) to (2, 2)
1104  EXPECT_EQ(m * Point(200, 300), Point(-1, -1));
1105  EXPECT_EQ(m * Point(500, 300), Point(2, -1));
1106  EXPECT_EQ(m * Point(500, 900), Point(2, 2));
1107  EXPECT_EQ(m * Point(200, 900), Point(-1, 2));
1108  }
1109 
1110  {
1111  // Checks for behavior with empty rects
1112 
1113  auto zero = Matrix::MakeScale({0.0, 0.0, 1.0});
1114 
1115  // Empty for width and/or height == 0
1116  EXPECT_EQ(IRect::MakeXYWH(10, 10, 0, 10).GetNormalizingTransform(), zero);
1117  EXPECT_EQ(IRect::MakeXYWH(10, 10, 10, 0).GetNormalizingTransform(), zero);
1118  EXPECT_EQ(IRect::MakeXYWH(10, 10, 0, 0).GetNormalizingTransform(), zero);
1119 
1120  // Empty for width and/or height < 0
1121  EXPECT_EQ(IRect::MakeXYWH(10, 10, -1, 10).GetNormalizingTransform(), zero);
1122  EXPECT_EQ(IRect::MakeXYWH(10, 10, 10, -1).GetNormalizingTransform(), zero);
1123  EXPECT_EQ(IRect::MakeXYWH(10, 10, -1, -1).GetNormalizingTransform(), zero);
1124  }
1125 }
1126 
1127 TEST(RectTest, RectXYWHIsEmpty) {
1128  auto nan = std::numeric_limits<Scalar>::quiet_NaN();
1129 
1130  // Non-empty
1131  EXPECT_FALSE(Rect::MakeXYWH(1.5, 2.3, 10.5, 7.2).IsEmpty());
1132 
1133  // Empty both width and height both 0 or negative, in all combinations
1134  EXPECT_TRUE(Rect::MakeXYWH(1.5, 2.3, 0.0, 0.0).IsEmpty());
1135  EXPECT_TRUE(Rect::MakeXYWH(1.5, 2.3, -1.0, -1.0).IsEmpty());
1136  EXPECT_TRUE(Rect::MakeXYWH(1.5, 2.3, 0.0, -1.0).IsEmpty());
1137  EXPECT_TRUE(Rect::MakeXYWH(1.5, 2.3, -1.0, 0.0).IsEmpty());
1138 
1139  // Empty for 0 or negative width or height (but not both at the same time)
1140  EXPECT_TRUE(Rect::MakeXYWH(1.5, 2.3, 10.5, 0.0).IsEmpty());
1141  EXPECT_TRUE(Rect::MakeXYWH(1.5, 2.3, 10.5, -1.0).IsEmpty());
1142  EXPECT_TRUE(Rect::MakeXYWH(1.5, 2.3, 0.0, 7.2).IsEmpty());
1143  EXPECT_TRUE(Rect::MakeXYWH(1.5, 2.3, -1.0, 7.2).IsEmpty());
1144 
1145  // Empty for NaN in width or height or both
1146  EXPECT_TRUE(Rect::MakeXYWH(1.5, 2.3, 10.5, nan).IsEmpty());
1147  EXPECT_TRUE(Rect::MakeXYWH(1.5, 2.3, nan, 7.2).IsEmpty());
1148  EXPECT_TRUE(Rect::MakeXYWH(1.5, 2.3, nan, nan).IsEmpty());
1149 }
1150 
1151 TEST(RectTest, IRectXYWHIsEmpty) {
1152  // Non-empty
1153  EXPECT_FALSE(IRect::MakeXYWH(1, 2, 10, 7).IsEmpty());
1154 
1155  // Empty both width and height both 0 or negative, in all combinations
1156  EXPECT_TRUE(IRect::MakeXYWH(1, 2, 0, 0).IsEmpty());
1157  EXPECT_TRUE(IRect::MakeXYWH(1, 2, -1, -1).IsEmpty());
1158  EXPECT_TRUE(IRect::MakeXYWH(1, 2, -1, 0).IsEmpty());
1159  EXPECT_TRUE(IRect::MakeXYWH(1, 2, 0, -1).IsEmpty());
1160 
1161  // Empty for 0 or negative width or height (but not both at the same time)
1162  EXPECT_TRUE(IRect::MakeXYWH(1, 2, 10, 0).IsEmpty());
1163  EXPECT_TRUE(IRect::MakeXYWH(1, 2, 10, -1).IsEmpty());
1164  EXPECT_TRUE(IRect::MakeXYWH(1, 2, 0, 7).IsEmpty());
1165  EXPECT_TRUE(IRect::MakeXYWH(1, 2, -1, 7).IsEmpty());
1166 }
1167 
1168 TEST(RectTest, MakePointBoundsQuad) {
1169  Quad quad = {
1170  Point(10, 10),
1171  Point(20, 10),
1172  Point(10, 20),
1173  Point(20, 20),
1174  };
1175  std::optional<Rect> bounds = Rect::MakePointBounds(quad);
1176  EXPECT_TRUE(bounds.has_value());
1177  if (bounds.has_value()) {
1178  EXPECT_TRUE(RectNear(bounds.value(), Rect::MakeLTRB(10, 10, 20, 20)));
1179  }
1180 }
1181 
1182 TEST(RectTest, IsSquare) {
1183  EXPECT_TRUE(Rect::MakeXYWH(10, 30, 20, 20).IsSquare());
1184  EXPECT_FALSE(Rect::MakeXYWH(10, 30, 20, 19).IsSquare());
1185  EXPECT_FALSE(Rect::MakeXYWH(10, 30, 19, 20).IsSquare());
1186  EXPECT_TRUE(Rect::MakeMaximum().IsSquare());
1187 
1188  EXPECT_TRUE(IRect::MakeXYWH(10, 30, 20, 20).IsSquare());
1189  EXPECT_FALSE(IRect::MakeXYWH(10, 30, 20, 19).IsSquare());
1190  EXPECT_FALSE(IRect::MakeXYWH(10, 30, 19, 20).IsSquare());
1191  EXPECT_TRUE(IRect::MakeMaximum().IsSquare());
1192 }
1193 
1194 TEST(RectTest, GetCenter) {
1195  EXPECT_EQ(Rect::MakeXYWH(10, 30, 20, 20).GetCenter(), Point(20, 40));
1196  EXPECT_EQ(Rect::MakeXYWH(10, 30, 20, 19).GetCenter(), Point(20, 39.5));
1197  EXPECT_EQ(Rect::MakeMaximum().GetCenter(), Point(0, 0));
1198 
1199  // Note that we expect a Point as the answer from an IRect
1200  EXPECT_EQ(IRect::MakeXYWH(10, 30, 20, 20).GetCenter(), Point(20, 40));
1201  EXPECT_EQ(IRect::MakeXYWH(10, 30, 20, 19).GetCenter(), Point(20, 39.5));
1202  EXPECT_EQ(IRect::MakeMaximum().GetCenter(), Point(0, 0));
1203 }
1204 
1205 TEST(RectTest, RectExpand) {
1206  auto rect = Rect::MakeLTRB(100, 100, 200, 200);
1207 
1208  // Expand(T amount)
1209  EXPECT_EQ(rect.Expand(10), Rect::MakeLTRB(90, 90, 210, 210));
1210  EXPECT_EQ(rect.Expand(-10), Rect::MakeLTRB(110, 110, 190, 190));
1211 
1212  // Expand(amount, amount)
1213  EXPECT_EQ(rect.Expand(10, 10), Rect::MakeLTRB(90, 90, 210, 210));
1214  EXPECT_EQ(rect.Expand(10, -10), Rect::MakeLTRB(90, 110, 210, 190));
1215  EXPECT_EQ(rect.Expand(-10, 10), Rect::MakeLTRB(110, 90, 190, 210));
1216  EXPECT_EQ(rect.Expand(-10, -10), Rect::MakeLTRB(110, 110, 190, 190));
1217 
1218  // Expand(amount, amount, amount, amount)
1219  EXPECT_EQ(rect.Expand(10, 20, 30, 40), Rect::MakeLTRB(90, 80, 230, 240));
1220  EXPECT_EQ(rect.Expand(-10, 20, 30, 40), Rect::MakeLTRB(110, 80, 230, 240));
1221  EXPECT_EQ(rect.Expand(10, -20, 30, 40), Rect::MakeLTRB(90, 120, 230, 240));
1222  EXPECT_EQ(rect.Expand(10, 20, -30, 40), Rect::MakeLTRB(90, 80, 170, 240));
1223  EXPECT_EQ(rect.Expand(10, 20, 30, -40), Rect::MakeLTRB(90, 80, 230, 160));
1224 
1225  // Expand(Point amount)
1226  EXPECT_EQ(rect.Expand(Point{10, 10}), Rect::MakeLTRB(90, 90, 210, 210));
1227  EXPECT_EQ(rect.Expand(Point{10, -10}), Rect::MakeLTRB(90, 110, 210, 190));
1228  EXPECT_EQ(rect.Expand(Point{-10, 10}), Rect::MakeLTRB(110, 90, 190, 210));
1229  EXPECT_EQ(rect.Expand(Point{-10, -10}), Rect::MakeLTRB(110, 110, 190, 190));
1230 
1231  // Expand(Size amount)
1232  EXPECT_EQ(rect.Expand(Size{10, 10}), Rect::MakeLTRB(90, 90, 210, 210));
1233  EXPECT_EQ(rect.Expand(Size{10, -10}), Rect::MakeLTRB(90, 110, 210, 190));
1234  EXPECT_EQ(rect.Expand(Size{-10, 10}), Rect::MakeLTRB(110, 90, 190, 210));
1235  EXPECT_EQ(rect.Expand(Size{-10, -10}), Rect::MakeLTRB(110, 110, 190, 190));
1236 }
1237 
1238 TEST(RectTest, IRectExpand) {
1239  auto rect = IRect::MakeLTRB(100, 100, 200, 200);
1240 
1241  // Expand(T amount)
1242  EXPECT_EQ(rect.Expand(10), IRect::MakeLTRB(90, 90, 210, 210));
1243  EXPECT_EQ(rect.Expand(-10), IRect::MakeLTRB(110, 110, 190, 190));
1244 
1245  // Expand(amount, amount)
1246  EXPECT_EQ(rect.Expand(10, 10), IRect::MakeLTRB(90, 90, 210, 210));
1247  EXPECT_EQ(rect.Expand(10, -10), IRect::MakeLTRB(90, 110, 210, 190));
1248  EXPECT_EQ(rect.Expand(-10, 10), IRect::MakeLTRB(110, 90, 190, 210));
1249  EXPECT_EQ(rect.Expand(-10, -10), IRect::MakeLTRB(110, 110, 190, 190));
1250 
1251  // Expand(amount, amount, amount, amount)
1252  EXPECT_EQ(rect.Expand(10, 20, 30, 40), IRect::MakeLTRB(90, 80, 230, 240));
1253  EXPECT_EQ(rect.Expand(-10, 20, 30, 40), IRect::MakeLTRB(110, 80, 230, 240));
1254  EXPECT_EQ(rect.Expand(10, -20, 30, 40), IRect::MakeLTRB(90, 120, 230, 240));
1255  EXPECT_EQ(rect.Expand(10, 20, -30, 40), IRect::MakeLTRB(90, 80, 170, 240));
1256  EXPECT_EQ(rect.Expand(10, 20, 30, -40), IRect::MakeLTRB(90, 80, 230, 160));
1257 
1258  // Expand(IPoint amount)
1259  EXPECT_EQ(rect.Expand(IPoint{10, 10}), IRect::MakeLTRB(90, 90, 210, 210));
1260  EXPECT_EQ(rect.Expand(IPoint{10, -10}), IRect::MakeLTRB(90, 110, 210, 190));
1261  EXPECT_EQ(rect.Expand(IPoint{-10, 10}), IRect::MakeLTRB(110, 90, 190, 210));
1262  EXPECT_EQ(rect.Expand(IPoint{-10, -10}), IRect::MakeLTRB(110, 110, 190, 190));
1263 
1264  // Expand(ISize amount)
1265  EXPECT_EQ(rect.Expand(ISize{10, 10}), IRect::MakeLTRB(90, 90, 210, 210));
1266  EXPECT_EQ(rect.Expand(ISize{10, -10}), IRect::MakeLTRB(90, 110, 210, 190));
1267  EXPECT_EQ(rect.Expand(ISize{-10, 10}), IRect::MakeLTRB(110, 90, 190, 210));
1268  EXPECT_EQ(rect.Expand(ISize{-10, -10}), IRect::MakeLTRB(110, 110, 190, 190));
1269 }
1270 
1271 TEST(RectTest, ContainsFloatingPoint) {
1272  auto rect1 =
1273  Rect::MakeXYWH(472.599945f, 440.999969f, 1102.80005f, 654.000061f);
1274  auto rect2 = Rect::MakeXYWH(724.f, 618.f, 600.f, 300.f);
1275  EXPECT_TRUE(rect1.Contains(rect2));
1276 }
1277 
1278 template <typename R>
1279 static constexpr inline R flip_lr(R rect) {
1280  return R::MakeLTRB(rect.GetRight(), rect.GetTop(), //
1281  rect.GetLeft(), rect.GetBottom());
1282 }
1283 
1284 template <typename R>
1285 static constexpr inline R flip_tb(R rect) {
1286  return R::MakeLTRB(rect.GetLeft(), rect.GetBottom(), //
1287  rect.GetRight(), rect.GetTop());
1288 }
1289 
1290 template <typename R>
1291 static constexpr inline R flip_lrtb(R rect) {
1292  return flip_lr(flip_tb(rect));
1293 }
1294 
1295 static constexpr inline Rect swap_nan(const Rect& rect, int index) {
1296  Scalar nan = std::numeric_limits<Scalar>::quiet_NaN();
1297  FML_DCHECK(index >= 0 && index <= 15);
1298  Scalar l = ((index & (1 << 0)) != 0) ? nan : rect.GetLeft();
1299  Scalar t = ((index & (1 << 1)) != 0) ? nan : rect.GetTop();
1300  Scalar r = ((index & (1 << 2)) != 0) ? nan : rect.GetRight();
1301  Scalar b = ((index & (1 << 3)) != 0) ? nan : rect.GetBottom();
1302  return Rect::MakeLTRB(l, t, r, b);
1303 }
1304 
1305 static constexpr inline Point swap_nan(const Point& point, int index) {
1306  Scalar nan = std::numeric_limits<Scalar>::quiet_NaN();
1307  FML_DCHECK(index >= 0 && index <= 3);
1308  Scalar x = ((index & (1 << 0)) != 0) ? nan : point.x;
1309  Scalar y = ((index & (1 << 1)) != 0) ? nan : point.y;
1310  return Point(x, y);
1311 }
1312 
1313 TEST(RectTest, RectUnion) {
1314  auto check_nans = [](const Rect& a, const Rect& b, const std::string& label) {
1315  ASSERT_TRUE(a.IsFinite()) << label;
1316  ASSERT_TRUE(b.IsFinite()) << label;
1317  ASSERT_FALSE(a.Union(b).IsEmpty());
1318 
1319  for (int i = 1; i < 16; i++) {
1320  // NaN in a produces b
1321  EXPECT_EQ(swap_nan(a, i).Union(b), b) << label << ", index = " << i;
1322  // NaN in b produces a
1323  EXPECT_EQ(a.Union(swap_nan(b, i)), a) << label << ", index = " << i;
1324  // NaN in both is empty
1325  for (int j = 1; j < 16; j++) {
1326  EXPECT_TRUE(swap_nan(a, i).Union(swap_nan(b, j)).IsEmpty())
1327  << label << ", indices = " << i << ", " << j;
1328  }
1329  }
1330  };
1331 
1332  auto check_empty_flips = [](const Rect& a, const Rect& b,
1333  const std::string& label) {
1334  ASSERT_FALSE(a.IsEmpty());
1335  // b is allowed to be empty
1336 
1337  // unflipped a vs flipped (empty) b yields a
1338  EXPECT_EQ(a.Union(flip_lr(b)), a) << label;
1339  EXPECT_EQ(a.Union(flip_tb(b)), a) << label;
1340  EXPECT_EQ(a.Union(flip_lrtb(b)), a) << label;
1341 
1342  // flipped (empty) a vs unflipped b yields b
1343  EXPECT_EQ(flip_lr(a).Union(b), b) << label;
1344  EXPECT_EQ(flip_tb(a).Union(b), b) << label;
1345  EXPECT_EQ(flip_lrtb(a).Union(b), b) << label;
1346 
1347  // flipped (empty) a vs flipped (empty) b yields empty
1348  EXPECT_TRUE(flip_lr(a).Union(flip_lr(b)).IsEmpty()) << label;
1349  EXPECT_TRUE(flip_tb(a).Union(flip_tb(b)).IsEmpty()) << label;
1350  EXPECT_TRUE(flip_lrtb(a).Union(flip_lrtb(b)).IsEmpty()) << label;
1351  };
1352 
1353  auto test = [&check_nans, &check_empty_flips](const Rect& a, const Rect& b,
1354  const Rect& result) {
1355  ASSERT_FALSE(a.IsEmpty()) << a;
1356  // b is allowed to be empty
1357 
1358  std::stringstream stream;
1359  stream << a << " union " << b;
1360  auto label = stream.str();
1361 
1362  EXPECT_EQ(a.Union(b), result) << label;
1363  EXPECT_EQ(b.Union(a), result) << label;
1364  check_empty_flips(a, b, label);
1365  check_nans(a, b, label);
1366  };
1367 
1368  {
1369  auto a = Rect::MakeXYWH(100, 100, 100, 100);
1370  auto b = Rect::MakeXYWH(0, 0, 0, 0);
1371  auto expected = Rect::MakeXYWH(100, 100, 100, 100);
1372  test(a, b, expected);
1373  }
1374 
1375  {
1376  auto a = Rect::MakeXYWH(100, 100, 100, 100);
1377  auto b = Rect::MakeXYWH(0, 0, 1, 1);
1378  auto expected = Rect::MakeXYWH(0, 0, 200, 200);
1379  test(a, b, expected);
1380  }
1381 
1382  {
1383  auto a = Rect::MakeXYWH(100, 100, 100, 100);
1384  auto b = Rect::MakeXYWH(10, 10, 1, 1);
1385  auto expected = Rect::MakeXYWH(10, 10, 190, 190);
1386  test(a, b, expected);
1387  }
1388 
1389  {
1390  auto a = Rect::MakeXYWH(0, 0, 100, 100);
1391  auto b = Rect::MakeXYWH(10, 10, 100, 100);
1392  auto expected = Rect::MakeXYWH(0, 0, 110, 110);
1393  test(a, b, expected);
1394  }
1395 
1396  {
1397  auto a = Rect::MakeXYWH(0, 0, 100, 100);
1398  auto b = Rect::MakeXYWH(100, 100, 100, 100);
1399  auto expected = Rect::MakeXYWH(0, 0, 200, 200);
1400  test(a, b, expected);
1401  }
1402 }
1403 
1404 TEST(RectTest, OptRectUnion) {
1405  auto a = Rect::MakeLTRB(0, 0, 100, 100);
1406  auto b = Rect::MakeLTRB(100, 100, 200, 200);
1407  auto c = Rect::MakeLTRB(100, 0, 200, 100);
1408 
1409  // NullOpt, NullOpt
1410  EXPECT_FALSE(Rect::Union(std::nullopt, std::nullopt).has_value());
1411  EXPECT_EQ(Rect::Union(std::nullopt, std::nullopt), std::nullopt);
1412 
1413  auto test1 = [](const Rect& r) {
1414  // Rect, NullOpt
1415  EXPECT_TRUE(Rect::Union(r, std::nullopt).has_value());
1416  EXPECT_EQ(Rect::Union(r, std::nullopt).value(), r);
1417 
1418  // OptRect, NullOpt
1419  EXPECT_TRUE(Rect::Union(std::optional(r), std::nullopt).has_value());
1420  EXPECT_EQ(Rect::Union(std::optional(r), std::nullopt).value(), r);
1421 
1422  // NullOpt, Rect
1423  EXPECT_TRUE(Rect::Union(std::nullopt, r).has_value());
1424  EXPECT_EQ(Rect::Union(std::nullopt, r).value(), r);
1425 
1426  // NullOpt, OptRect
1427  EXPECT_TRUE(Rect::Union(std::nullopt, std::optional(r)).has_value());
1428  EXPECT_EQ(Rect::Union(std::nullopt, std::optional(r)).value(), r);
1429  };
1430 
1431  test1(a);
1432  test1(b);
1433  test1(c);
1434 
1435  auto test2 = [](const Rect& a, const Rect& b, const Rect& u) {
1436  ASSERT_EQ(a.Union(b), u);
1437 
1438  // Rect, OptRect
1439  EXPECT_TRUE(Rect::Union(a, std::optional(b)).has_value());
1440  EXPECT_EQ(Rect::Union(a, std::optional(b)).value(), u);
1441 
1442  // OptRect, Rect
1443  EXPECT_TRUE(Rect::Union(std::optional(a), b).has_value());
1444  EXPECT_EQ(Rect::Union(std::optional(a), b).value(), u);
1445 
1446  // OptRect, OptRect
1447  EXPECT_TRUE(Rect::Union(std::optional(a), std::optional(b)).has_value());
1448  EXPECT_EQ(Rect::Union(std::optional(a), std::optional(b)).value(), u);
1449  };
1450 
1451  test2(a, b, Rect::MakeLTRB(0, 0, 200, 200));
1452  test2(a, c, Rect::MakeLTRB(0, 0, 200, 100));
1453  test2(b, c, Rect::MakeLTRB(100, 0, 200, 200));
1454 }
1455 
1456 TEST(RectTest, IRectUnion) {
1457  auto check_empty_flips = [](const IRect& a, const IRect& b,
1458  const std::string& label) {
1459  ASSERT_FALSE(a.IsEmpty());
1460  // b is allowed to be empty
1461 
1462  // unflipped a vs flipped (empty) b yields a
1463  EXPECT_EQ(a.Union(flip_lr(b)), a) << label;
1464  EXPECT_EQ(a.Union(flip_tb(b)), a) << label;
1465  EXPECT_EQ(a.Union(flip_lrtb(b)), a) << label;
1466 
1467  // flipped (empty) a vs unflipped b yields b
1468  EXPECT_EQ(flip_lr(a).Union(b), b) << label;
1469  EXPECT_EQ(flip_tb(a).Union(b), b) << label;
1470  EXPECT_EQ(flip_lrtb(a).Union(b), b) << label;
1471 
1472  // flipped (empty) a vs flipped (empty) b yields empty
1473  EXPECT_TRUE(flip_lr(a).Union(flip_lr(b)).IsEmpty()) << label;
1474  EXPECT_TRUE(flip_tb(a).Union(flip_tb(b)).IsEmpty()) << label;
1475  EXPECT_TRUE(flip_lrtb(a).Union(flip_lrtb(b)).IsEmpty()) << label;
1476  };
1477 
1478  auto test = [&check_empty_flips](const IRect& a, const IRect& b,
1479  const IRect& result) {
1480  ASSERT_FALSE(a.IsEmpty()) << a;
1481  // b is allowed to be empty
1482 
1483  std::stringstream stream;
1484  stream << a << " union " << b;
1485  auto label = stream.str();
1486 
1487  EXPECT_EQ(a.Union(b), result) << label;
1488  EXPECT_EQ(b.Union(a), result) << label;
1489  check_empty_flips(a, b, label);
1490  };
1491 
1492  {
1493  auto a = IRect::MakeXYWH(100, 100, 100, 100);
1494  auto b = IRect::MakeXYWH(0, 0, 0, 0);
1495  auto expected = IRect::MakeXYWH(100, 100, 100, 100);
1496  test(a, b, expected);
1497  }
1498 
1499  {
1500  auto a = IRect::MakeXYWH(100, 100, 100, 100);
1501  auto b = IRect::MakeXYWH(0, 0, 1, 1);
1502  auto expected = IRect::MakeXYWH(0, 0, 200, 200);
1503  test(a, b, expected);
1504  }
1505 
1506  {
1507  auto a = IRect::MakeXYWH(100, 100, 100, 100);
1508  auto b = IRect::MakeXYWH(10, 10, 1, 1);
1509  auto expected = IRect::MakeXYWH(10, 10, 190, 190);
1510  test(a, b, expected);
1511  }
1512 
1513  {
1514  auto a = IRect::MakeXYWH(0, 0, 100, 100);
1515  auto b = IRect::MakeXYWH(10, 10, 100, 100);
1516  auto expected = IRect::MakeXYWH(0, 0, 110, 110);
1517  test(a, b, expected);
1518  }
1519 
1520  {
1521  auto a = IRect::MakeXYWH(0, 0, 100, 100);
1522  auto b = IRect::MakeXYWH(100, 100, 100, 100);
1523  auto expected = IRect::MakeXYWH(0, 0, 200, 200);
1524  test(a, b, expected);
1525  }
1526 }
1527 
1528 TEST(RectTest, OptIRectUnion) {
1529  auto a = IRect::MakeLTRB(0, 0, 100, 100);
1530  auto b = IRect::MakeLTRB(100, 100, 200, 200);
1531  auto c = IRect::MakeLTRB(100, 0, 200, 100);
1532 
1533  // NullOpt, NullOpt
1534  EXPECT_FALSE(IRect::Union(std::nullopt, std::nullopt).has_value());
1535  EXPECT_EQ(IRect::Union(std::nullopt, std::nullopt), std::nullopt);
1536 
1537  auto test1 = [](const IRect& r) {
1538  // Rect, NullOpt
1539  EXPECT_TRUE(IRect::Union(r, std::nullopt).has_value());
1540  EXPECT_EQ(IRect::Union(r, std::nullopt).value(), r);
1541 
1542  // OptRect, NullOpt
1543  EXPECT_TRUE(IRect::Union(std::optional(r), std::nullopt).has_value());
1544  EXPECT_EQ(IRect::Union(std::optional(r), std::nullopt).value(), r);
1545 
1546  // NullOpt, Rect
1547  EXPECT_TRUE(IRect::Union(std::nullopt, r).has_value());
1548  EXPECT_EQ(IRect::Union(std::nullopt, r).value(), r);
1549 
1550  // NullOpt, OptRect
1551  EXPECT_TRUE(IRect::Union(std::nullopt, std::optional(r)).has_value());
1552  EXPECT_EQ(IRect::Union(std::nullopt, std::optional(r)).value(), r);
1553  };
1554 
1555  test1(a);
1556  test1(b);
1557  test1(c);
1558 
1559  auto test2 = [](const IRect& a, const IRect& b, const IRect& u) {
1560  ASSERT_EQ(a.Union(b), u);
1561 
1562  // Rect, OptRect
1563  EXPECT_TRUE(IRect::Union(a, std::optional(b)).has_value());
1564  EXPECT_EQ(IRect::Union(a, std::optional(b)).value(), u);
1565 
1566  // OptRect, Rect
1567  EXPECT_TRUE(IRect::Union(std::optional(a), b).has_value());
1568  EXPECT_EQ(IRect::Union(std::optional(a), b).value(), u);
1569 
1570  // OptRect, OptRect
1571  EXPECT_TRUE(IRect::Union(std::optional(a), std::optional(b)).has_value());
1572  EXPECT_EQ(IRect::Union(std::optional(a), std::optional(b)).value(), u);
1573  };
1574 
1575  test2(a, b, IRect::MakeLTRB(0, 0, 200, 200));
1576  test2(a, c, IRect::MakeLTRB(0, 0, 200, 100));
1577  test2(b, c, IRect::MakeLTRB(100, 0, 200, 200));
1578 }
1579 
1580 TEST(RectTest, RectIntersection) {
1581  auto check_nans = [](const Rect& a, const Rect& b, const std::string& label) {
1582  ASSERT_TRUE(a.IsFinite()) << label;
1583  ASSERT_TRUE(b.IsFinite()) << label;
1584 
1585  for (int i = 1; i < 16; i++) {
1586  // NaN in a produces empty
1587  EXPECT_FALSE(swap_nan(a, i).Intersection(b).has_value())
1588  << label << ", index = " << i;
1589  // NaN in b produces empty
1590  EXPECT_FALSE(a.Intersection(swap_nan(b, i)).has_value())
1591  << label << ", index = " << i;
1592  // NaN in both is empty
1593  for (int j = 1; j < 16; j++) {
1594  EXPECT_FALSE(swap_nan(a, i).Intersection(swap_nan(b, j)).has_value())
1595  << label << ", indices = " << i << ", " << j;
1596  }
1597  }
1598  };
1599 
1600  auto check_empty_flips = [](const Rect& a, const Rect& b,
1601  const std::string& label) {
1602  ASSERT_FALSE(a.IsEmpty());
1603  // b is allowed to be empty
1604 
1605  // unflipped a vs flipped (empty) b yields a
1606  EXPECT_FALSE(a.Intersection(flip_lr(b)).has_value()) << label;
1607  EXPECT_FALSE(a.Intersection(flip_tb(b)).has_value()) << label;
1608  EXPECT_FALSE(a.Intersection(flip_lrtb(b)).has_value()) << label;
1609 
1610  // flipped (empty) a vs unflipped b yields b
1611  EXPECT_FALSE(flip_lr(a).Intersection(b).has_value()) << label;
1612  EXPECT_FALSE(flip_tb(a).Intersection(b).has_value()) << label;
1613  EXPECT_FALSE(flip_lrtb(a).Intersection(b).has_value()) << label;
1614 
1615  // flipped (empty) a vs flipped (empty) b yields empty
1616  EXPECT_FALSE(flip_lr(a).Intersection(flip_lr(b)).has_value()) << label;
1617  EXPECT_FALSE(flip_tb(a).Intersection(flip_tb(b)).has_value()) << label;
1618  EXPECT_FALSE(flip_lrtb(a).Intersection(flip_lrtb(b)).has_value()) << label;
1619  };
1620 
1621  auto test_non_empty = [&check_nans, &check_empty_flips](
1622  const Rect& a, const Rect& b, const Rect& result) {
1623  ASSERT_FALSE(a.IsEmpty()) << a;
1624  // b is allowed to be empty
1625 
1626  std::stringstream stream;
1627  stream << a << " union " << b;
1628  auto label = stream.str();
1629 
1630  EXPECT_TRUE(a.Intersection(b).has_value()) << label;
1631  EXPECT_TRUE(b.Intersection(a).has_value()) << label;
1632  EXPECT_EQ(a.Intersection(b), result) << label;
1633  EXPECT_EQ(b.Intersection(a), result) << label;
1634  check_empty_flips(a, b, label);
1635  check_nans(a, b, label);
1636  };
1637 
1638  auto test_empty = [&check_nans, &check_empty_flips](const Rect& a,
1639  const Rect& b) {
1640  ASSERT_FALSE(a.IsEmpty()) << a;
1641  // b is allowed to be empty
1642 
1643  std::stringstream stream;
1644  stream << a << " union " << b;
1645  auto label = stream.str();
1646 
1647  EXPECT_FALSE(a.Intersection(b).has_value()) << label;
1648  EXPECT_FALSE(b.Intersection(a).has_value()) << label;
1649  check_empty_flips(a, b, label);
1650  check_nans(a, b, label);
1651  };
1652 
1653  {
1654  auto a = Rect::MakeXYWH(100, 100, 100, 100);
1655  auto b = Rect::MakeXYWH(0, 0, 0, 0);
1656 
1657  test_empty(a, b);
1658  }
1659 
1660  {
1661  auto a = Rect::MakeXYWH(100, 100, 100, 100);
1662  auto b = Rect::MakeXYWH(10, 10, 0, 0);
1663 
1664  test_empty(a, b);
1665  }
1666 
1667  {
1668  auto a = Rect::MakeXYWH(0, 0, 100, 100);
1669  auto b = Rect::MakeXYWH(10, 10, 100, 100);
1670  auto expected = Rect::MakeXYWH(10, 10, 90, 90);
1671 
1672  test_non_empty(a, b, expected);
1673  }
1674 
1675  {
1676  auto a = Rect::MakeXYWH(0, 0, 100, 100);
1677  auto b = Rect::MakeXYWH(100, 100, 100, 100);
1678 
1679  test_empty(a, b);
1680  }
1681 
1682  {
1683  auto a = Rect::MakeMaximum();
1684  auto b = Rect::MakeXYWH(10, 10, 300, 300);
1685 
1686  test_non_empty(a, b, b);
1687  }
1688 
1689  {
1690  auto a = Rect::MakeMaximum();
1691  auto b = Rect::MakeMaximum();
1692 
1693  test_non_empty(a, b, Rect::MakeMaximum());
1694  }
1695 }
1696 
1697 TEST(RectTest, OptRectIntersection) {
1698  auto a = Rect::MakeLTRB(0, 0, 110, 110);
1699  auto b = Rect::MakeLTRB(100, 100, 200, 200);
1700  auto c = Rect::MakeLTRB(100, 0, 200, 110);
1701 
1702  // NullOpt, NullOpt
1703  EXPECT_FALSE(Rect::Intersection(std::nullopt, std::nullopt).has_value());
1704  EXPECT_EQ(Rect::Intersection(std::nullopt, std::nullopt), std::nullopt);
1705 
1706  auto test1 = [](const Rect& r) {
1707  // Rect, NullOpt
1708  EXPECT_TRUE(Rect::Intersection(r, std::nullopt).has_value());
1709  EXPECT_EQ(Rect::Intersection(r, std::nullopt).value(), r);
1710 
1711  // OptRect, NullOpt
1712  EXPECT_TRUE(Rect::Intersection(std::optional(r), std::nullopt).has_value());
1713  EXPECT_EQ(Rect::Intersection(std::optional(r), std::nullopt).value(), r);
1714 
1715  // NullOpt, Rect
1716  EXPECT_TRUE(Rect::Intersection(std::nullopt, r).has_value());
1717  EXPECT_EQ(Rect::Intersection(std::nullopt, r).value(), r);
1718 
1719  // NullOpt, OptRect
1720  EXPECT_TRUE(Rect::Intersection(std::nullopt, std::optional(r)).has_value());
1721  EXPECT_EQ(Rect::Intersection(std::nullopt, std::optional(r)).value(), r);
1722  };
1723 
1724  test1(a);
1725  test1(b);
1726  test1(c);
1727 
1728  auto test2 = [](const Rect& a, const Rect& b, const Rect& i) {
1729  ASSERT_EQ(a.Intersection(b), i);
1730 
1731  // Rect, OptRect
1732  EXPECT_TRUE(Rect::Intersection(a, std::optional(b)).has_value());
1733  EXPECT_EQ(Rect::Intersection(a, std::optional(b)).value(), i);
1734 
1735  // OptRect, Rect
1736  EXPECT_TRUE(Rect::Intersection(std::optional(a), b).has_value());
1737  EXPECT_EQ(Rect::Intersection(std::optional(a), b).value(), i);
1738 
1739  // OptRect, OptRect
1740  EXPECT_TRUE(
1741  Rect::Intersection(std::optional(a), std::optional(b)).has_value());
1742  EXPECT_EQ(Rect::Intersection(std::optional(a), std::optional(b)).value(),
1743  i);
1744  };
1745 
1746  test2(a, b, Rect::MakeLTRB(100, 100, 110, 110));
1747  test2(a, c, Rect::MakeLTRB(100, 0, 110, 110));
1748  test2(b, c, Rect::MakeLTRB(100, 100, 200, 110));
1749 }
1750 
1751 TEST(RectTest, IRectIntersection) {
1752  auto check_empty_flips = [](const IRect& a, const IRect& b,
1753  const std::string& label) {
1754  ASSERT_FALSE(a.IsEmpty());
1755  // b is allowed to be empty
1756 
1757  // unflipped a vs flipped (empty) b yields a
1758  EXPECT_FALSE(a.Intersection(flip_lr(b)).has_value()) << label;
1759  EXPECT_FALSE(a.Intersection(flip_tb(b)).has_value()) << label;
1760  EXPECT_FALSE(a.Intersection(flip_lrtb(b)).has_value()) << label;
1761 
1762  // flipped (empty) a vs unflipped b yields b
1763  EXPECT_FALSE(flip_lr(a).Intersection(b).has_value()) << label;
1764  EXPECT_FALSE(flip_tb(a).Intersection(b).has_value()) << label;
1765  EXPECT_FALSE(flip_lrtb(a).Intersection(b).has_value()) << label;
1766 
1767  // flipped (empty) a vs flipped (empty) b yields empty
1768  EXPECT_FALSE(flip_lr(a).Intersection(flip_lr(b)).has_value()) << label;
1769  EXPECT_FALSE(flip_tb(a).Intersection(flip_tb(b)).has_value()) << label;
1770  EXPECT_FALSE(flip_lrtb(a).Intersection(flip_lrtb(b)).has_value()) << label;
1771  };
1772 
1773  auto test_non_empty = [&check_empty_flips](const IRect& a, const IRect& b,
1774  const IRect& result) {
1775  ASSERT_FALSE(a.IsEmpty()) << a;
1776  // b is allowed to be empty
1777 
1778  std::stringstream stream;
1779  stream << a << " union " << b;
1780  auto label = stream.str();
1781 
1782  EXPECT_TRUE(a.Intersection(b).has_value()) << label;
1783  EXPECT_TRUE(b.Intersection(a).has_value()) << label;
1784  EXPECT_EQ(a.Intersection(b), result) << label;
1785  EXPECT_EQ(b.Intersection(a), result) << label;
1786  check_empty_flips(a, b, label);
1787  };
1788 
1789  auto test_empty = [&check_empty_flips](const IRect& a, const IRect& b) {
1790  ASSERT_FALSE(a.IsEmpty()) << a;
1791  // b is allowed to be empty
1792 
1793  std::stringstream stream;
1794  stream << a << " union " << b;
1795  auto label = stream.str();
1796 
1797  EXPECT_FALSE(a.Intersection(b).has_value()) << label;
1798  EXPECT_FALSE(b.Intersection(a).has_value()) << label;
1799  check_empty_flips(a, b, label);
1800  };
1801 
1802  {
1803  auto a = IRect::MakeXYWH(100, 100, 100, 100);
1804  auto b = IRect::MakeXYWH(0, 0, 0, 0);
1805 
1806  test_empty(a, b);
1807  }
1808 
1809  {
1810  auto a = IRect::MakeXYWH(100, 100, 100, 100);
1811  auto b = IRect::MakeXYWH(10, 10, 0, 0);
1812 
1813  test_empty(a, b);
1814  }
1815 
1816  {
1817  auto a = IRect::MakeXYWH(0, 0, 100, 100);
1818  auto b = IRect::MakeXYWH(10, 10, 100, 100);
1819  auto expected = IRect::MakeXYWH(10, 10, 90, 90);
1820 
1821  test_non_empty(a, b, expected);
1822  }
1823 
1824  {
1825  auto a = IRect::MakeXYWH(0, 0, 100, 100);
1826  auto b = IRect::MakeXYWH(100, 100, 100, 100);
1827 
1828  test_empty(a, b);
1829  }
1830 
1831  {
1832  auto a = IRect::MakeMaximum();
1833  auto b = IRect::MakeXYWH(10, 10, 300, 300);
1834 
1835  test_non_empty(a, b, b);
1836  }
1837 
1838  {
1839  auto a = IRect::MakeMaximum();
1840  auto b = IRect::MakeMaximum();
1841 
1842  test_non_empty(a, b, IRect::MakeMaximum());
1843  }
1844 }
1845 
1846 TEST(RectTest, OptIRectIntersection) {
1847  auto a = IRect::MakeLTRB(0, 0, 110, 110);
1848  auto b = IRect::MakeLTRB(100, 100, 200, 200);
1849  auto c = IRect::MakeLTRB(100, 0, 200, 110);
1850 
1851  // NullOpt, NullOpt
1852  EXPECT_FALSE(IRect::Intersection(std::nullopt, std::nullopt).has_value());
1853  EXPECT_EQ(IRect::Intersection(std::nullopt, std::nullopt), std::nullopt);
1854 
1855  auto test1 = [](const IRect& r) {
1856  // Rect, NullOpt
1857  EXPECT_TRUE(IRect::Intersection(r, std::nullopt).has_value());
1858  EXPECT_EQ(IRect::Intersection(r, std::nullopt).value(), r);
1859 
1860  // OptRect, NullOpt
1861  EXPECT_TRUE(
1862  IRect::Intersection(std::optional(r), std::nullopt).has_value());
1863  EXPECT_EQ(IRect::Intersection(std::optional(r), std::nullopt).value(), r);
1864 
1865  // NullOpt, Rect
1866  EXPECT_TRUE(IRect::Intersection(std::nullopt, r).has_value());
1867  EXPECT_EQ(IRect::Intersection(std::nullopt, r).value(), r);
1868 
1869  // NullOpt, OptRect
1870  EXPECT_TRUE(
1871  IRect::Intersection(std::nullopt, std::optional(r)).has_value());
1872  EXPECT_EQ(IRect::Intersection(std::nullopt, std::optional(r)).value(), r);
1873  };
1874 
1875  test1(a);
1876  test1(b);
1877  test1(c);
1878 
1879  auto test2 = [](const IRect& a, const IRect& b, const IRect& i) {
1880  ASSERT_EQ(a.Intersection(b), i);
1881 
1882  // Rect, OptRect
1883  EXPECT_TRUE(IRect::Intersection(a, std::optional(b)).has_value());
1884  EXPECT_EQ(IRect::Intersection(a, std::optional(b)).value(), i);
1885 
1886  // OptRect, Rect
1887  EXPECT_TRUE(IRect::Intersection(std::optional(a), b).has_value());
1888  EXPECT_EQ(IRect::Intersection(std::optional(a), b).value(), i);
1889 
1890  // OptRect, OptRect
1891  EXPECT_TRUE(
1892  IRect::Intersection(std::optional(a), std::optional(b)).has_value());
1893  EXPECT_EQ(IRect::Intersection(std::optional(a), std::optional(b)).value(),
1894  i);
1895  };
1896 
1897  test2(a, b, IRect::MakeLTRB(100, 100, 110, 110));
1898  test2(a, c, IRect::MakeLTRB(100, 0, 110, 110));
1899  test2(b, c, IRect::MakeLTRB(100, 100, 200, 110));
1900 }
1901 
1902 TEST(RectTest, RectIntersectsWithRect) {
1903  auto check_nans = [](const Rect& a, const Rect& b, const std::string& label) {
1904  ASSERT_TRUE(a.IsFinite()) << label;
1905  ASSERT_TRUE(b.IsFinite()) << label;
1906 
1907  for (int i = 1; i < 16; i++) {
1908  // NaN in a produces b
1909  EXPECT_FALSE(swap_nan(a, i).IntersectsWithRect(b))
1910  << label << ", index = " << i;
1911  // NaN in b produces a
1912  EXPECT_FALSE(a.IntersectsWithRect(swap_nan(b, i)))
1913  << label << ", index = " << i;
1914  // NaN in both is empty
1915  for (int j = 1; j < 16; j++) {
1916  EXPECT_FALSE(swap_nan(a, i).IntersectsWithRect(swap_nan(b, j)))
1917  << label << ", indices = " << i << ", " << j;
1918  }
1919  }
1920  };
1921 
1922  auto check_empty_flips = [](const Rect& a, const Rect& b,
1923  const std::string& label) {
1924  ASSERT_FALSE(a.IsEmpty());
1925  // b is allowed to be empty
1926 
1927  // unflipped a vs flipped (empty) b yields a
1928  EXPECT_FALSE(a.IntersectsWithRect(flip_lr(b))) << label;
1929  EXPECT_FALSE(a.IntersectsWithRect(flip_tb(b))) << label;
1930  EXPECT_FALSE(a.IntersectsWithRect(flip_lrtb(b))) << label;
1931 
1932  // flipped (empty) a vs unflipped b yields b
1933  EXPECT_FALSE(flip_lr(a).IntersectsWithRect(b)) << label;
1934  EXPECT_FALSE(flip_tb(a).IntersectsWithRect(b)) << label;
1935  EXPECT_FALSE(flip_lrtb(a).IntersectsWithRect(b)) << label;
1936 
1937  // flipped (empty) a vs flipped (empty) b yields empty
1938  EXPECT_FALSE(flip_lr(a).IntersectsWithRect(flip_lr(b))) << label;
1939  EXPECT_FALSE(flip_tb(a).IntersectsWithRect(flip_tb(b))) << label;
1940  EXPECT_FALSE(flip_lrtb(a).IntersectsWithRect(flip_lrtb(b))) << label;
1941  };
1942 
1943  auto test_non_empty = [&check_nans, &check_empty_flips](const Rect& a,
1944  const Rect& b) {
1945  ASSERT_FALSE(a.IsEmpty()) << a;
1946  // b is allowed to be empty
1947 
1948  std::stringstream stream;
1949  stream << a << " union " << b;
1950  auto label = stream.str();
1951 
1952  EXPECT_TRUE(a.IntersectsWithRect(b)) << label;
1953  EXPECT_TRUE(b.IntersectsWithRect(a)) << label;
1954  check_empty_flips(a, b, label);
1955  check_nans(a, b, label);
1956  };
1957 
1958  auto test_empty = [&check_nans, &check_empty_flips](const Rect& a,
1959  const Rect& b) {
1960  ASSERT_FALSE(a.IsEmpty()) << a;
1961  // b is allowed to be empty
1962 
1963  std::stringstream stream;
1964  stream << a << " union " << b;
1965  auto label = stream.str();
1966 
1967  EXPECT_FALSE(a.IntersectsWithRect(b)) << label;
1968  EXPECT_FALSE(b.IntersectsWithRect(a)) << label;
1969  check_empty_flips(a, b, label);
1970  check_nans(a, b, label);
1971  };
1972 
1973  {
1974  auto a = Rect::MakeXYWH(100, 100, 100, 100);
1975  auto b = Rect::MakeXYWH(0, 0, 0, 0);
1976 
1977  test_empty(a, b);
1978  }
1979 
1980  {
1981  auto a = Rect::MakeXYWH(100, 100, 100, 100);
1982  auto b = Rect::MakeXYWH(10, 10, 0, 0);
1983 
1984  test_empty(a, b);
1985  }
1986 
1987  {
1988  auto a = Rect::MakeXYWH(0, 0, 100, 100);
1989  auto b = Rect::MakeXYWH(10, 10, 100, 100);
1990 
1991  test_non_empty(a, b);
1992  }
1993 
1994  {
1995  auto a = Rect::MakeXYWH(0, 0, 100, 100);
1996  auto b = Rect::MakeXYWH(100, 100, 100, 100);
1997 
1998  test_empty(a, b);
1999  }
2000 
2001  {
2002  auto a = Rect::MakeMaximum();
2003  auto b = Rect::MakeXYWH(10, 10, 100, 100);
2004 
2005  test_non_empty(a, b);
2006  }
2007 
2008  {
2009  auto a = Rect::MakeMaximum();
2010  auto b = Rect::MakeMaximum();
2011 
2012  test_non_empty(a, b);
2013  }
2014 }
2015 
2016 TEST(RectTest, IRectIntersectsWithRect) {
2017  auto check_empty_flips = [](const IRect& a, const IRect& b,
2018  const std::string& label) {
2019  ASSERT_FALSE(a.IsEmpty());
2020  // b is allowed to be empty
2021 
2022  // unflipped a vs flipped (empty) b yields a
2023  EXPECT_FALSE(a.IntersectsWithRect(flip_lr(b))) << label;
2024  EXPECT_FALSE(a.IntersectsWithRect(flip_tb(b))) << label;
2025  EXPECT_FALSE(a.IntersectsWithRect(flip_lrtb(b))) << label;
2026 
2027  // flipped (empty) a vs unflipped b yields b
2028  EXPECT_FALSE(flip_lr(a).IntersectsWithRect(b)) << label;
2029  EXPECT_FALSE(flip_tb(a).IntersectsWithRect(b)) << label;
2030  EXPECT_FALSE(flip_lrtb(a).IntersectsWithRect(b)) << label;
2031 
2032  // flipped (empty) a vs flipped (empty) b yields empty
2033  EXPECT_FALSE(flip_lr(a).IntersectsWithRect(flip_lr(b))) << label;
2034  EXPECT_FALSE(flip_tb(a).IntersectsWithRect(flip_tb(b))) << label;
2035  EXPECT_FALSE(flip_lrtb(a).IntersectsWithRect(flip_lrtb(b))) << label;
2036  };
2037 
2038  auto test_non_empty = [&check_empty_flips](const IRect& a, const IRect& b) {
2039  ASSERT_FALSE(a.IsEmpty()) << a;
2040  // b is allowed to be empty
2041 
2042  std::stringstream stream;
2043  stream << a << " union " << b;
2044  auto label = stream.str();
2045 
2046  EXPECT_TRUE(a.IntersectsWithRect(b)) << label;
2047  EXPECT_TRUE(b.IntersectsWithRect(a)) << label;
2048  check_empty_flips(a, b, label);
2049  };
2050 
2051  auto test_empty = [&check_empty_flips](const IRect& a, const IRect& b) {
2052  ASSERT_FALSE(a.IsEmpty()) << a;
2053  // b is allowed to be empty
2054 
2055  std::stringstream stream;
2056  stream << a << " union " << b;
2057  auto label = stream.str();
2058 
2059  EXPECT_FALSE(a.IntersectsWithRect(b)) << label;
2060  EXPECT_FALSE(b.IntersectsWithRect(a)) << label;
2061  check_empty_flips(a, b, label);
2062  };
2063 
2064  {
2065  auto a = IRect::MakeXYWH(100, 100, 100, 100);
2066  auto b = IRect::MakeXYWH(0, 0, 0, 0);
2067 
2068  test_empty(a, b);
2069  }
2070 
2071  {
2072  auto a = IRect::MakeXYWH(100, 100, 100, 100);
2073  auto b = IRect::MakeXYWH(10, 10, 0, 0);
2074 
2075  test_empty(a, b);
2076  }
2077 
2078  {
2079  auto a = IRect::MakeXYWH(0, 0, 100, 100);
2080  auto b = IRect::MakeXYWH(10, 10, 100, 100);
2081 
2082  test_non_empty(a, b);
2083  }
2084 
2085  {
2086  auto a = IRect::MakeXYWH(0, 0, 100, 100);
2087  auto b = IRect::MakeXYWH(100, 100, 100, 100);
2088 
2089  test_empty(a, b);
2090  }
2091 
2092  {
2093  auto a = IRect::MakeMaximum();
2094  auto b = IRect::MakeXYWH(10, 10, 100, 100);
2095 
2096  test_non_empty(a, b);
2097  }
2098 
2099  {
2100  auto a = IRect::MakeMaximum();
2101  auto b = IRect::MakeMaximum();
2102 
2103  test_non_empty(a, b);
2104  }
2105 }
2106 
2107 TEST(RectTest, RectContainsPoint) {
2108  auto check_nans = [](const Rect& rect, const Point& point,
2109  const std::string& label) {
2110  ASSERT_TRUE(rect.IsFinite()) << label;
2111  ASSERT_TRUE(point.IsFinite()) << label;
2112 
2113  for (int i = 1; i < 16; i++) {
2114  EXPECT_FALSE(swap_nan(rect, i).Contains(point))
2115  << label << ", index = " << i;
2116  for (int j = 1; j < 4; j++) {
2117  EXPECT_FALSE(swap_nan(rect, i).Contains(swap_nan(point, j)))
2118  << label << ", indices = " << i << ", " << j;
2119  }
2120  }
2121  };
2122 
2123  auto check_empty_flips = [](const Rect& rect, const Point& point,
2124  const std::string& label) {
2125  ASSERT_FALSE(rect.IsEmpty());
2126 
2127  EXPECT_FALSE(flip_lr(rect).Contains(point)) << label;
2128  EXPECT_FALSE(flip_tb(rect).Contains(point)) << label;
2129  EXPECT_FALSE(flip_lrtb(rect).Contains(point)) << label;
2130  };
2131 
2132  auto test_inside = [&check_nans, &check_empty_flips](const Rect& rect,
2133  const Point& point) {
2134  ASSERT_FALSE(rect.IsEmpty()) << rect;
2135 
2136  std::stringstream stream;
2137  stream << rect << " contains " << point;
2138  auto label = stream.str();
2139 
2140  EXPECT_TRUE(rect.Contains(point)) << label;
2141  check_empty_flips(rect, point, label);
2142  check_nans(rect, point, label);
2143  };
2144 
2145  auto test_outside = [&check_nans, &check_empty_flips](const Rect& rect,
2146  const Point& point) {
2147  ASSERT_FALSE(rect.IsEmpty()) << rect;
2148 
2149  std::stringstream stream;
2150  stream << rect << " contains " << point;
2151  auto label = stream.str();
2152 
2153  EXPECT_FALSE(rect.Contains(point)) << label;
2154  check_empty_flips(rect, point, label);
2155  check_nans(rect, point, label);
2156  };
2157 
2158  {
2159  // Origin is inclusive
2160  auto r = Rect::MakeXYWH(100, 100, 100, 100);
2161  auto p = Point(100, 100);
2162 
2163  test_inside(r, p);
2164  }
2165  {
2166  // Size is exclusive
2167  auto r = Rect::MakeXYWH(100, 100, 100, 100);
2168  auto p = Point(200, 200);
2169 
2170  test_outside(r, p);
2171  }
2172  {
2173  auto r = Rect::MakeXYWH(100, 100, 100, 100);
2174  auto p = Point(99, 99);
2175 
2176  test_outside(r, p);
2177  }
2178  {
2179  auto r = Rect::MakeXYWH(100, 100, 100, 100);
2180  auto p = Point(199, 199);
2181 
2182  test_inside(r, p);
2183  }
2184 
2185  {
2186  auto r = Rect::MakeMaximum();
2187  auto p = Point(199, 199);
2188 
2189  test_inside(r, p);
2190  }
2191 }
2192 
2193 TEST(RectTest, IRectContainsIPoint) {
2194  auto check_empty_flips = [](const IRect& rect, const IPoint& point,
2195  const std::string& label) {
2196  ASSERT_FALSE(rect.IsEmpty());
2197 
2198  EXPECT_FALSE(flip_lr(rect).Contains(point)) << label;
2199  EXPECT_FALSE(flip_tb(rect).Contains(point)) << label;
2200  EXPECT_FALSE(flip_lrtb(rect).Contains(point)) << label;
2201  };
2202 
2203  auto test_inside = [&check_empty_flips](const IRect& rect,
2204  const IPoint& point) {
2205  ASSERT_FALSE(rect.IsEmpty()) << rect;
2206 
2207  std::stringstream stream;
2208  stream << rect << " contains " << point;
2209  auto label = stream.str();
2210 
2211  EXPECT_TRUE(rect.Contains(point)) << label;
2212  check_empty_flips(rect, point, label);
2213  };
2214 
2215  auto test_outside = [&check_empty_flips](const IRect& rect,
2216  const IPoint& point) {
2217  ASSERT_FALSE(rect.IsEmpty()) << rect;
2218 
2219  std::stringstream stream;
2220  stream << rect << " contains " << point;
2221  auto label = stream.str();
2222 
2223  EXPECT_FALSE(rect.Contains(point)) << label;
2224  check_empty_flips(rect, point, label);
2225  };
2226 
2227  {
2228  // Origin is inclusive
2229  auto r = IRect::MakeXYWH(100, 100, 100, 100);
2230  auto p = IPoint(100, 100);
2231 
2232  test_inside(r, p);
2233  }
2234  {
2235  // Size is exclusive
2236  auto r = IRect::MakeXYWH(100, 100, 100, 100);
2237  auto p = IPoint(200, 200);
2238 
2239  test_outside(r, p);
2240  }
2241  {
2242  auto r = IRect::MakeXYWH(100, 100, 100, 100);
2243  auto p = IPoint(99, 99);
2244 
2245  test_outside(r, p);
2246  }
2247  {
2248  auto r = IRect::MakeXYWH(100, 100, 100, 100);
2249  auto p = IPoint(199, 199);
2250 
2251  test_inside(r, p);
2252  }
2253 
2254  {
2255  auto r = IRect::MakeMaximum();
2256  auto p = IPoint(199, 199);
2257 
2258  test_inside(r, p);
2259  }
2260 }
2261 
2262 TEST(RectTest, RectContainsInclusivePoint) {
2263  auto check_nans = [](const Rect& rect, const Point& point,
2264  const std::string& label) {
2265  ASSERT_TRUE(rect.IsFinite()) << label;
2266  ASSERT_TRUE(point.IsFinite()) << label;
2267 
2268  for (int i = 1; i < 16; i++) {
2269  EXPECT_FALSE(swap_nan(rect, i).ContainsInclusive(point))
2270  << label << ", index = " << i;
2271  for (int j = 1; j < 4; j++) {
2272  EXPECT_FALSE(swap_nan(rect, i).ContainsInclusive(swap_nan(point, j)))
2273  << label << ", indices = " << i << ", " << j;
2274  }
2275  }
2276  };
2277 
2278  auto check_empty_flips = [](const Rect& rect, const Point& point,
2279  const std::string& label) {
2280  ASSERT_FALSE(rect.IsEmpty());
2281 
2282  EXPECT_FALSE(flip_lr(rect).ContainsInclusive(point)) << label;
2283  EXPECT_FALSE(flip_tb(rect).ContainsInclusive(point)) << label;
2284  EXPECT_FALSE(flip_lrtb(rect).ContainsInclusive(point)) << label;
2285  };
2286 
2287  auto test_inside = [&check_nans, &check_empty_flips](const Rect& rect,
2288  const Point& point) {
2289  ASSERT_FALSE(rect.IsEmpty()) << rect;
2290 
2291  std::stringstream stream;
2292  stream << rect << " contains " << point;
2293  auto label = stream.str();
2294 
2295  EXPECT_TRUE(rect.ContainsInclusive(point)) << label;
2296  check_empty_flips(rect, point, label);
2297  check_nans(rect, point, label);
2298  };
2299 
2300  auto test_outside = [&check_nans, &check_empty_flips](const Rect& rect,
2301  const Point& point) {
2302  ASSERT_FALSE(rect.IsEmpty()) << rect;
2303 
2304  std::stringstream stream;
2305  stream << rect << " contains " << point;
2306  auto label = stream.str();
2307 
2308  EXPECT_FALSE(rect.ContainsInclusive(point)) << label;
2309  check_empty_flips(rect, point, label);
2310  check_nans(rect, point, label);
2311  };
2312 
2313  {
2314  // Origin is inclusive
2315  auto r = Rect::MakeXYWH(100, 100, 100, 100);
2316  auto p = Point(100, 100);
2317 
2318  test_inside(r, p);
2319  }
2320  {
2321  // Size is inclusive
2322  auto r = Rect::MakeXYWH(100, 100, 100, 100);
2323  auto p = Point(200, 200);
2324 
2325  test_inside(r, p);
2326  }
2327  {
2328  // Size + epsilon is exclusive
2329  auto r = Rect::MakeXYWH(100, 100, 100, 100);
2330  auto p = Point(200 + kEhCloseEnough, 200 + kEhCloseEnough);
2331 
2332  test_outside(r, p);
2333  }
2334  {
2335  auto r = Rect::MakeXYWH(100, 100, 100, 100);
2336  auto p = Point(99, 99);
2337 
2338  test_outside(r, p);
2339  }
2340  {
2341  auto r = Rect::MakeXYWH(100, 100, 100, 100);
2342  auto p = Point(199, 199);
2343 
2344  test_inside(r, p);
2345  }
2346 
2347  {
2348  auto r = Rect::MakeMaximum();
2349  auto p = Point(199, 199);
2350 
2351  test_inside(r, p);
2352  }
2353 }
2354 
2355 TEST(RectTest, IRectContainsInclusiveIPoint) {
2356  auto check_empty_flips = [](const IRect& rect, const IPoint& point,
2357  const std::string& label) {
2358  ASSERT_FALSE(rect.IsEmpty());
2359 
2360  EXPECT_FALSE(flip_lr(rect).ContainsInclusive(point)) << label;
2361  EXPECT_FALSE(flip_tb(rect).ContainsInclusive(point)) << label;
2362  EXPECT_FALSE(flip_lrtb(rect).ContainsInclusive(point)) << label;
2363  };
2364 
2365  auto test_inside = [&check_empty_flips](const IRect& rect,
2366  const IPoint& point) {
2367  ASSERT_FALSE(rect.IsEmpty()) << rect;
2368 
2369  std::stringstream stream;
2370  stream << rect << " contains " << point;
2371  auto label = stream.str();
2372 
2373  EXPECT_TRUE(rect.ContainsInclusive(point)) << label;
2374  check_empty_flips(rect, point, label);
2375  };
2376 
2377  auto test_outside = [&check_empty_flips](const IRect& rect,
2378  const IPoint& point) {
2379  ASSERT_FALSE(rect.IsEmpty()) << rect;
2380 
2381  std::stringstream stream;
2382  stream << rect << " contains " << point;
2383  auto label = stream.str();
2384 
2385  EXPECT_FALSE(rect.ContainsInclusive(point)) << label;
2386  check_empty_flips(rect, point, label);
2387  };
2388 
2389  {
2390  // Origin is inclusive
2391  auto r = IRect::MakeXYWH(100, 100, 100, 100);
2392  auto p = IPoint(100, 100);
2393 
2394  test_inside(r, p);
2395  }
2396  {
2397  // Size is inclusive
2398  auto r = IRect::MakeXYWH(100, 100, 100, 100);
2399  auto p = IPoint(200, 200);
2400 
2401  test_inside(r, p);
2402  }
2403  {
2404  // Size + "epsilon" is exclusive
2405  auto r = IRect::MakeXYWH(100, 100, 100, 100);
2406  auto p = IPoint(201, 201);
2407 
2408  test_outside(r, p);
2409  }
2410  {
2411  auto r = IRect::MakeXYWH(100, 100, 100, 100);
2412  auto p = IPoint(99, 99);
2413 
2414  test_outside(r, p);
2415  }
2416  {
2417  auto r = IRect::MakeXYWH(100, 100, 100, 100);
2418  auto p = IPoint(199, 199);
2419 
2420  test_inside(r, p);
2421  }
2422 
2423  {
2424  auto r = IRect::MakeMaximum();
2425  auto p = IPoint(199, 199);
2426 
2427  test_inside(r, p);
2428  }
2429 }
2430 
2431 TEST(RectTest, RectContainsRect) {
2432  auto check_nans = [](const Rect& a, const Rect& b, const std::string& label) {
2433  ASSERT_TRUE(a.IsFinite()) << label;
2434  ASSERT_TRUE(b.IsFinite()) << label;
2435  ASSERT_FALSE(a.IsEmpty());
2436 
2437  for (int i = 1; i < 16; i++) {
2438  // NaN in a produces false
2439  EXPECT_FALSE(swap_nan(a, i).Contains(b)) << label << ", index = " << i;
2440  // NaN in b produces false
2441  EXPECT_TRUE(a.Contains(swap_nan(b, i))) << label << ", index = " << i;
2442  // NaN in both is false
2443  for (int j = 1; j < 16; j++) {
2444  EXPECT_FALSE(swap_nan(a, i).Contains(swap_nan(b, j)))
2445  << label << ", indices = " << i << ", " << j;
2446  }
2447  }
2448  };
2449 
2450  auto check_empty_flips = [](const Rect& a, const Rect& b,
2451  const std::string& label) {
2452  ASSERT_FALSE(a.IsEmpty());
2453  // test b rects are allowed to have 0 w/h, but not be backwards
2454  ASSERT_FALSE(b.GetLeft() > b.GetRight() || b.GetTop() > b.GetBottom());
2455 
2456  // unflipped a vs flipped (empty) b yields false
2457  EXPECT_TRUE(a.Contains(flip_lr(b))) << label;
2458  EXPECT_TRUE(a.Contains(flip_tb(b))) << label;
2459  EXPECT_TRUE(a.Contains(flip_lrtb(b))) << label;
2460 
2461  // flipped (empty) a vs unflipped b yields false
2462  EXPECT_FALSE(flip_lr(a).Contains(b)) << label;
2463  EXPECT_FALSE(flip_tb(a).Contains(b)) << label;
2464  EXPECT_FALSE(flip_lrtb(a).Contains(b)) << label;
2465 
2466  // flipped (empty) a vs flipped (empty) b yields empty
2467  EXPECT_FALSE(flip_lr(a).Contains(flip_lr(b))) << label;
2468  EXPECT_FALSE(flip_tb(a).Contains(flip_tb(b))) << label;
2469  EXPECT_FALSE(flip_lrtb(a).Contains(flip_lrtb(b))) << label;
2470  };
2471 
2472  auto test_inside = [&check_nans, &check_empty_flips](const Rect& a,
2473  const Rect& b) {
2474  ASSERT_FALSE(a.IsEmpty()) << a;
2475  // test b rects are allowed to have 0 w/h, but not be backwards
2476  ASSERT_FALSE(b.GetLeft() > b.GetRight() || b.GetTop() > b.GetBottom());
2477 
2478  std::stringstream stream;
2479  stream << a << " contains " << b;
2480  auto label = stream.str();
2481 
2482  EXPECT_TRUE(a.Contains(b)) << label;
2483  check_empty_flips(a, b, label);
2484  check_nans(a, b, label);
2485  };
2486 
2487  auto test_not_inside = [&check_nans, &check_empty_flips](const Rect& a,
2488  const Rect& b) {
2489  ASSERT_FALSE(a.IsEmpty()) << a;
2490  // If b was empty, it would be contained and should not be tested with
2491  // this function - use |test_inside| instead.
2492  ASSERT_FALSE(b.IsEmpty()) << b;
2493 
2494  std::stringstream stream;
2495  stream << a << " contains " << b;
2496  auto label = stream.str();
2497 
2498  EXPECT_FALSE(a.Contains(b)) << label;
2499  check_empty_flips(a, b, label);
2500  check_nans(a, b, label);
2501  };
2502 
2503  {
2504  auto a = Rect::MakeXYWH(100, 100, 100, 100);
2505 
2506  test_inside(a, a);
2507  }
2508  {
2509  auto a = Rect::MakeXYWH(100, 100, 100, 100);
2510  auto b = Rect::MakeXYWH(0, 0, 0, 0);
2511 
2512  test_inside(a, b);
2513  }
2514  {
2515  auto a = Rect::MakeXYWH(100, 100, 100, 100);
2516  auto b = Rect::MakeXYWH(150, 150, 20, 20);
2517 
2518  test_inside(a, b);
2519  }
2520  {
2521  auto a = Rect::MakeXYWH(100, 100, 100, 100);
2522  auto b = Rect::MakeXYWH(150, 150, 100, 100);
2523 
2524  test_not_inside(a, b);
2525  }
2526  {
2527  auto a = Rect::MakeXYWH(100, 100, 100, 100);
2528  auto b = Rect::MakeXYWH(50, 50, 100, 100);
2529 
2530  test_not_inside(a, b);
2531  }
2532  {
2533  auto a = Rect::MakeXYWH(100, 100, 100, 100);
2534  auto b = Rect::MakeXYWH(0, 0, 300, 300);
2535 
2536  test_not_inside(a, b);
2537  }
2538  {
2539  auto a = Rect::MakeMaximum();
2540  auto b = Rect::MakeXYWH(0, 0, 300, 300);
2541 
2542  test_inside(a, b);
2543  }
2544 }
2545 
2546 TEST(RectTest, IRectContainsIRect) {
2547  auto check_empty_flips = [](const IRect& a, const IRect& b,
2548  const std::string& label) {
2549  ASSERT_FALSE(a.IsEmpty());
2550  // test b rects are allowed to have 0 w/h, but not be backwards
2551  ASSERT_FALSE(b.GetLeft() > b.GetRight() || b.GetTop() > b.GetBottom());
2552 
2553  // unflipped a vs flipped (empty) b yields true
2554  EXPECT_TRUE(a.Contains(flip_lr(b))) << label;
2555  EXPECT_TRUE(a.Contains(flip_tb(b))) << label;
2556  EXPECT_TRUE(a.Contains(flip_lrtb(b))) << label;
2557 
2558  // flipped (empty) a vs unflipped b yields false
2559  EXPECT_FALSE(flip_lr(a).Contains(b)) << label;
2560  EXPECT_FALSE(flip_tb(a).Contains(b)) << label;
2561  EXPECT_FALSE(flip_lrtb(a).Contains(b)) << label;
2562 
2563  // flipped (empty) a vs flipped (empty) b yields empty
2564  EXPECT_FALSE(flip_lr(a).Contains(flip_lr(b))) << label;
2565  EXPECT_FALSE(flip_tb(a).Contains(flip_tb(b))) << label;
2566  EXPECT_FALSE(flip_lrtb(a).Contains(flip_lrtb(b))) << label;
2567  };
2568 
2569  auto test_inside = [&check_empty_flips](const IRect& a, const IRect& b) {
2570  ASSERT_FALSE(a.IsEmpty()) << a;
2571  // test b rects are allowed to have 0 w/h, but not be backwards
2572  ASSERT_FALSE(b.GetLeft() > b.GetRight() || b.GetTop() > b.GetBottom());
2573 
2574  std::stringstream stream;
2575  stream << a << " contains " << b;
2576  auto label = stream.str();
2577 
2578  EXPECT_TRUE(a.Contains(b)) << label;
2579  check_empty_flips(a, b, label);
2580  };
2581 
2582  auto test_not_inside = [&check_empty_flips](const IRect& a, const IRect& b) {
2583  ASSERT_FALSE(a.IsEmpty()) << a;
2584  // If b was empty, it would be contained and should not be tested with
2585  // this function - use |test_inside| instead.
2586  ASSERT_FALSE(b.IsEmpty()) << b;
2587 
2588  std::stringstream stream;
2589  stream << a << " contains " << b;
2590  auto label = stream.str();
2591 
2592  EXPECT_FALSE(a.Contains(b)) << label;
2593  check_empty_flips(a, b, label);
2594  };
2595 
2596  {
2597  auto a = IRect::MakeXYWH(100, 100, 100, 100);
2598 
2599  test_inside(a, a);
2600  }
2601  {
2602  auto a = IRect::MakeXYWH(100, 100, 100, 100);
2603  auto b = IRect::MakeXYWH(0, 0, 0, 0);
2604 
2605  test_inside(a, b);
2606  }
2607  {
2608  auto a = IRect::MakeXYWH(100, 100, 100, 100);
2609  auto b = IRect::MakeXYWH(150, 150, 20, 20);
2610 
2611  test_inside(a, b);
2612  }
2613  {
2614  auto a = IRect::MakeXYWH(100, 100, 100, 100);
2615  auto b = IRect::MakeXYWH(150, 150, 100, 100);
2616 
2617  test_not_inside(a, b);
2618  }
2619  {
2620  auto a = IRect::MakeXYWH(100, 100, 100, 100);
2621  auto b = IRect::MakeXYWH(50, 50, 100, 100);
2622 
2623  test_not_inside(a, b);
2624  }
2625  {
2626  auto a = IRect::MakeXYWH(100, 100, 100, 100);
2627  auto b = IRect::MakeXYWH(0, 0, 300, 300);
2628 
2629  test_not_inside(a, b);
2630  }
2631  {
2632  auto a = IRect::MakeMaximum();
2633  auto b = IRect::MakeXYWH(0, 0, 300, 300);
2634 
2635  test_inside(a, b);
2636  }
2637 }
2638 
2639 TEST(RectTest, RectCutOut) {
2640  Rect cull_rect = Rect::MakeLTRB(20, 20, 40, 40);
2641 
2642  auto check_nans = [&cull_rect](const Rect& diff_rect,
2643  const std::string& label) {
2644  EXPECT_TRUE(cull_rect.IsFinite()) << label;
2645  EXPECT_TRUE(diff_rect.IsFinite()) << label;
2646 
2647  for (int i = 1; i < 16; i++) {
2648  // NaN in cull_rect produces empty
2649  EXPECT_FALSE(swap_nan(cull_rect, i).Cutout(diff_rect).has_value())
2650  << label << ", index " << i;
2651  EXPECT_EQ(swap_nan(cull_rect, i).CutoutOrEmpty(diff_rect), Rect())
2652  << label << ", index " << i;
2653 
2654  // NaN in diff_rect is nop
2655  EXPECT_TRUE(cull_rect.Cutout(swap_nan(diff_rect, i)).has_value())
2656  << label << ", index " << i;
2657  EXPECT_EQ(cull_rect.CutoutOrEmpty(swap_nan(diff_rect, i)), cull_rect)
2658  << label << ", index " << i;
2659 
2660  for (int j = 1; j < 16; j++) {
2661  // NaN in both is also empty
2662  EXPECT_FALSE(
2663  swap_nan(cull_rect, i).Cutout(swap_nan(diff_rect, j)).has_value())
2664  << label << ", indices " << i << ", " << j;
2665  EXPECT_EQ(swap_nan(cull_rect, i).CutoutOrEmpty(swap_nan(diff_rect, j)),
2666  Rect())
2667  << label << ", indices " << i << ", " << j;
2668  }
2669  }
2670  };
2671 
2672  auto check_empty_flips = [&cull_rect](const Rect& diff_rect,
2673  const std::string& label) {
2674  EXPECT_FALSE(cull_rect.IsEmpty()) << label;
2675  EXPECT_FALSE(diff_rect.IsEmpty()) << label;
2676 
2677  // unflipped cull_rect vs flipped(empty) diff_rect
2678  // == cull_rect
2679  EXPECT_TRUE(cull_rect.Cutout(flip_lr(diff_rect)).has_value()) << label;
2680  EXPECT_EQ(cull_rect.Cutout(flip_lr(diff_rect)), cull_rect) << label;
2681  EXPECT_TRUE(cull_rect.Cutout(flip_tb(diff_rect)).has_value()) << label;
2682  EXPECT_EQ(cull_rect.Cutout(flip_tb(diff_rect)), cull_rect) << label;
2683  EXPECT_TRUE(cull_rect.Cutout(flip_lrtb(diff_rect)).has_value()) << label;
2684  EXPECT_EQ(cull_rect.Cutout(flip_lrtb(diff_rect)), cull_rect) << label;
2685 
2686  // flipped(empty) cull_rect vs unflipped diff_rect
2687  // == empty
2688  EXPECT_FALSE(flip_lr(cull_rect).Cutout(diff_rect).has_value()) << label;
2689  EXPECT_EQ(flip_lr(cull_rect).CutoutOrEmpty(diff_rect), Rect()) << label;
2690  EXPECT_FALSE(flip_tb(cull_rect).Cutout(diff_rect).has_value()) << label;
2691  EXPECT_EQ(flip_tb(cull_rect).CutoutOrEmpty(diff_rect), Rect()) << label;
2692  EXPECT_FALSE(flip_lrtb(cull_rect).Cutout(diff_rect).has_value()) << label;
2693  EXPECT_EQ(flip_lrtb(cull_rect).CutoutOrEmpty(diff_rect), Rect()) << label;
2694 
2695  // flipped(empty) cull_rect vs flipped(empty) diff_rect
2696  // == empty
2697  EXPECT_FALSE(flip_lr(cull_rect).Cutout(flip_lr(diff_rect)).has_value())
2698  << label;
2699  EXPECT_EQ(flip_lr(cull_rect).CutoutOrEmpty(flip_lr(diff_rect)), Rect())
2700  << label;
2701  EXPECT_FALSE(flip_tb(cull_rect).Cutout(flip_tb(diff_rect)).has_value())
2702  << label;
2703  EXPECT_EQ(flip_tb(cull_rect).CutoutOrEmpty(flip_tb(diff_rect)), Rect())
2704  << label;
2705  EXPECT_FALSE(flip_lrtb(cull_rect).Cutout(flip_lrtb(diff_rect)).has_value())
2706  << label;
2707  EXPECT_EQ(flip_lrtb(cull_rect).CutoutOrEmpty(flip_lrtb(diff_rect)), Rect())
2708  << label;
2709  };
2710 
2711  auto non_reducing = [&cull_rect, &check_empty_flips, &check_nans](
2712  const Rect& diff_rect, const std::string& label) {
2713  EXPECT_EQ(cull_rect.Cutout(diff_rect), cull_rect) << label;
2714  EXPECT_EQ(cull_rect.CutoutOrEmpty(diff_rect), cull_rect) << label;
2715  check_empty_flips(diff_rect, label);
2716  check_nans(diff_rect, label);
2717  };
2718 
2719  auto reducing = [&cull_rect, &check_empty_flips, &check_nans](
2720  const Rect& diff_rect, const Rect& result_rect,
2721  const std::string& label) {
2722  EXPECT_TRUE(!result_rect.IsEmpty());
2723  EXPECT_EQ(cull_rect.Cutout(diff_rect), result_rect) << label;
2724  EXPECT_EQ(cull_rect.CutoutOrEmpty(diff_rect), result_rect) << label;
2725  check_empty_flips(diff_rect, label);
2726  check_nans(diff_rect, label);
2727  };
2728 
2729  auto emptying = [&cull_rect, &check_empty_flips, &check_nans](
2730  const Rect& diff_rect, const std::string& label) {
2731  EXPECT_FALSE(cull_rect.Cutout(diff_rect).has_value()) << label;
2732  EXPECT_EQ(cull_rect.CutoutOrEmpty(diff_rect), Rect()) << label;
2733  check_empty_flips(diff_rect, label);
2734  check_nans(diff_rect, label);
2735  };
2736 
2737  // Skim the corners and edge
2738  non_reducing(Rect::MakeLTRB(10, 10, 20, 20), "outside UL corner");
2739  non_reducing(Rect::MakeLTRB(20, 10, 40, 20), "Above");
2740  non_reducing(Rect::MakeLTRB(40, 10, 50, 20), "outside UR corner");
2741  non_reducing(Rect::MakeLTRB(40, 20, 50, 40), "Right");
2742  non_reducing(Rect::MakeLTRB(40, 40, 50, 50), "outside LR corner");
2743  non_reducing(Rect::MakeLTRB(20, 40, 40, 50), "Below");
2744  non_reducing(Rect::MakeLTRB(10, 40, 20, 50), "outside LR corner");
2745  non_reducing(Rect::MakeLTRB(10, 20, 20, 40), "Left");
2746 
2747  // Overlap corners
2748  non_reducing(Rect::MakeLTRB(15, 15, 25, 25), "covering UL corner");
2749  non_reducing(Rect::MakeLTRB(35, 15, 45, 25), "covering UR corner");
2750  non_reducing(Rect::MakeLTRB(35, 35, 45, 45), "covering LR corner");
2751  non_reducing(Rect::MakeLTRB(15, 35, 25, 45), "covering LL corner");
2752 
2753  // Overlap edges, but not across an entire side
2754  non_reducing(Rect::MakeLTRB(20, 15, 39, 25), "Top edge left-biased");
2755  non_reducing(Rect::MakeLTRB(21, 15, 40, 25), "Top edge, right biased");
2756  non_reducing(Rect::MakeLTRB(35, 20, 45, 39), "Right edge, top-biased");
2757  non_reducing(Rect::MakeLTRB(35, 21, 45, 40), "Right edge, bottom-biased");
2758  non_reducing(Rect::MakeLTRB(20, 35, 39, 45), "Bottom edge, left-biased");
2759  non_reducing(Rect::MakeLTRB(21, 35, 40, 45), "Bottom edge, right-biased");
2760  non_reducing(Rect::MakeLTRB(15, 20, 25, 39), "Left edge, top-biased");
2761  non_reducing(Rect::MakeLTRB(15, 21, 25, 40), "Left edge, bottom-biased");
2762 
2763  // Slice all the way through the middle
2764  non_reducing(Rect::MakeLTRB(25, 15, 35, 45), "Vertical interior slice");
2765  non_reducing(Rect::MakeLTRB(15, 25, 45, 35), "Horizontal interior slice");
2766 
2767  // Slice off each edge
2768  reducing(Rect::MakeLTRB(20, 15, 40, 25), //
2769  Rect::MakeLTRB(20, 25, 40, 40), //
2770  "Slice off top");
2771  reducing(Rect::MakeLTRB(35, 20, 45, 40), //
2772  Rect::MakeLTRB(20, 20, 35, 40), //
2773  "Slice off right");
2774  reducing(Rect::MakeLTRB(20, 35, 40, 45), //
2775  Rect::MakeLTRB(20, 20, 40, 35), //
2776  "Slice off bottom");
2777  reducing(Rect::MakeLTRB(15, 20, 25, 40), //
2778  Rect::MakeLTRB(25, 20, 40, 40), //
2779  "Slice off left");
2780 
2781  // cull rect contains diff rect
2782  non_reducing(Rect::MakeLTRB(21, 21, 39, 39), "Contained, non-covering");
2783 
2784  // cull rect equals diff rect
2785  emptying(cull_rect, "Perfectly covering");
2786 
2787  // diff rect contains cull rect
2788  emptying(Rect::MakeLTRB(15, 15, 45, 45), "Smothering");
2789 }
2790 
2791 TEST(RectTest, IRectCutOut) {
2792  IRect cull_rect = IRect::MakeLTRB(20, 20, 40, 40);
2793 
2794  auto check_empty_flips = [&cull_rect](const IRect& diff_rect,
2795  const std::string& label) {
2796  EXPECT_FALSE(diff_rect.IsEmpty());
2797  EXPECT_FALSE(cull_rect.IsEmpty());
2798 
2799  // unflipped cull_rect vs flipped(empty) diff_rect
2800  // == cull_rect
2801  EXPECT_TRUE(cull_rect.Cutout(flip_lr(diff_rect)).has_value()) << label;
2802  EXPECT_EQ(cull_rect.Cutout(flip_lr(diff_rect)), cull_rect) << label;
2803  EXPECT_TRUE(cull_rect.Cutout(flip_tb(diff_rect)).has_value()) << label;
2804  EXPECT_EQ(cull_rect.Cutout(flip_tb(diff_rect)), cull_rect) << label;
2805  EXPECT_TRUE(cull_rect.Cutout(flip_lrtb(diff_rect)).has_value()) << label;
2806  EXPECT_EQ(cull_rect.Cutout(flip_lrtb(diff_rect)), cull_rect) << label;
2807 
2808  // flipped(empty) cull_rect vs flipped(empty) diff_rect
2809  // == empty
2810  EXPECT_FALSE(flip_lr(cull_rect).Cutout(diff_rect).has_value()) << label;
2811  EXPECT_EQ(flip_lr(cull_rect).CutoutOrEmpty(diff_rect), IRect()) << label;
2812  EXPECT_FALSE(flip_tb(cull_rect).Cutout(diff_rect).has_value()) << label;
2813  EXPECT_EQ(flip_tb(cull_rect).CutoutOrEmpty(diff_rect), IRect()) << label;
2814  EXPECT_FALSE(flip_lrtb(cull_rect).Cutout(diff_rect).has_value()) << label;
2815  EXPECT_EQ(flip_lrtb(cull_rect).CutoutOrEmpty(diff_rect), IRect()) << label;
2816 
2817  // flipped(empty) cull_rect vs unflipped diff_rect
2818  // == empty
2819  EXPECT_FALSE(flip_lr(cull_rect).Cutout(flip_lr(diff_rect)).has_value())
2820  << label;
2821  EXPECT_EQ(flip_lr(cull_rect).CutoutOrEmpty(flip_lr(diff_rect)), IRect())
2822  << label;
2823  EXPECT_FALSE(flip_tb(cull_rect).Cutout(flip_tb(diff_rect)).has_value())
2824  << label;
2825  EXPECT_EQ(flip_tb(cull_rect).CutoutOrEmpty(flip_tb(diff_rect)), IRect())
2826  << label;
2827  EXPECT_FALSE(flip_lrtb(cull_rect).Cutout(flip_lrtb(diff_rect)).has_value())
2828  << label;
2829  EXPECT_EQ(flip_lrtb(cull_rect).CutoutOrEmpty(flip_lrtb(diff_rect)), IRect())
2830  << label;
2831  };
2832 
2833  auto non_reducing = [&cull_rect, &check_empty_flips](
2834  const IRect& diff_rect, const std::string& label) {
2835  EXPECT_EQ(cull_rect.Cutout(diff_rect), cull_rect) << label;
2836  EXPECT_EQ(cull_rect.CutoutOrEmpty(diff_rect), cull_rect) << label;
2837  check_empty_flips(diff_rect, label);
2838  };
2839 
2840  auto reducing = [&cull_rect, &check_empty_flips](const IRect& diff_rect,
2841  const IRect& result_rect,
2842  const std::string& label) {
2843  EXPECT_TRUE(!result_rect.IsEmpty());
2844  EXPECT_EQ(cull_rect.Cutout(diff_rect), result_rect) << label;
2845  EXPECT_EQ(cull_rect.CutoutOrEmpty(diff_rect), result_rect) << label;
2846  check_empty_flips(diff_rect, label);
2847  };
2848 
2849  auto emptying = [&cull_rect, &check_empty_flips](const IRect& diff_rect,
2850  const std::string& label) {
2851  EXPECT_FALSE(cull_rect.Cutout(diff_rect).has_value()) << label;
2852  EXPECT_EQ(cull_rect.CutoutOrEmpty(diff_rect), IRect()) << label;
2853  check_empty_flips(diff_rect, label);
2854  };
2855 
2856  // Skim the corners and edge
2857  non_reducing(IRect::MakeLTRB(10, 10, 20, 20), "outside UL corner");
2858  non_reducing(IRect::MakeLTRB(20, 10, 40, 20), "Above");
2859  non_reducing(IRect::MakeLTRB(40, 10, 50, 20), "outside UR corner");
2860  non_reducing(IRect::MakeLTRB(40, 20, 50, 40), "Right");
2861  non_reducing(IRect::MakeLTRB(40, 40, 50, 50), "outside LR corner");
2862  non_reducing(IRect::MakeLTRB(20, 40, 40, 50), "Below");
2863  non_reducing(IRect::MakeLTRB(10, 40, 20, 50), "outside LR corner");
2864  non_reducing(IRect::MakeLTRB(10, 20, 20, 40), "Left");
2865 
2866  // Overlap corners
2867  non_reducing(IRect::MakeLTRB(15, 15, 25, 25), "covering UL corner");
2868  non_reducing(IRect::MakeLTRB(35, 15, 45, 25), "covering UR corner");
2869  non_reducing(IRect::MakeLTRB(35, 35, 45, 45), "covering LR corner");
2870  non_reducing(IRect::MakeLTRB(15, 35, 25, 45), "covering LL corner");
2871 
2872  // Overlap edges, but not across an entire side
2873  non_reducing(IRect::MakeLTRB(20, 15, 39, 25), "Top edge left-biased");
2874  non_reducing(IRect::MakeLTRB(21, 15, 40, 25), "Top edge, right biased");
2875  non_reducing(IRect::MakeLTRB(35, 20, 45, 39), "Right edge, top-biased");
2876  non_reducing(IRect::MakeLTRB(35, 21, 45, 40), "Right edge, bottom-biased");
2877  non_reducing(IRect::MakeLTRB(20, 35, 39, 45), "Bottom edge, left-biased");
2878  non_reducing(IRect::MakeLTRB(21, 35, 40, 45), "Bottom edge, right-biased");
2879  non_reducing(IRect::MakeLTRB(15, 20, 25, 39), "Left edge, top-biased");
2880  non_reducing(IRect::MakeLTRB(15, 21, 25, 40), "Left edge, bottom-biased");
2881 
2882  // Slice all the way through the middle
2883  non_reducing(IRect::MakeLTRB(25, 15, 35, 45), "Vertical interior slice");
2884  non_reducing(IRect::MakeLTRB(15, 25, 45, 35), "Horizontal interior slice");
2885 
2886  // Slice off each edge
2887  reducing(IRect::MakeLTRB(20, 15, 40, 25), //
2888  IRect::MakeLTRB(20, 25, 40, 40), //
2889  "Slice off top");
2890  reducing(IRect::MakeLTRB(35, 20, 45, 40), //
2891  IRect::MakeLTRB(20, 20, 35, 40), //
2892  "Slice off right");
2893  reducing(IRect::MakeLTRB(20, 35, 40, 45), //
2894  IRect::MakeLTRB(20, 20, 40, 35), //
2895  "Slice off bottom");
2896  reducing(IRect::MakeLTRB(15, 20, 25, 40), //
2897  IRect::MakeLTRB(25, 20, 40, 40), //
2898  "Slice off left");
2899 
2900  // cull rect contains diff rect
2901  non_reducing(IRect::MakeLTRB(21, 21, 39, 39), "Contained, non-covering");
2902 
2903  // cull rect equals diff rect
2904  emptying(cull_rect, "Perfectly covering");
2905 
2906  // diff rect contains cull rect
2907  emptying(IRect::MakeLTRB(15, 15, 45, 45), "Smothering");
2908 }
2909 
2910 TEST(RectTest, RectGetPoints) {
2911  {
2912  Rect r = Rect::MakeXYWH(100, 200, 300, 400);
2913  auto points = r.GetPoints();
2914  EXPECT_POINT_NEAR(points[0], Point(100, 200));
2915  EXPECT_POINT_NEAR(points[1], Point(400, 200));
2916  EXPECT_POINT_NEAR(points[2], Point(100, 600));
2917  EXPECT_POINT_NEAR(points[3], Point(400, 600));
2918  }
2919 
2920  {
2921  Rect r = Rect::MakeMaximum();
2922  auto points = r.GetPoints();
2923  EXPECT_EQ(points[0], Point(std::numeric_limits<float>::lowest(),
2924  std::numeric_limits<float>::lowest()));
2925  EXPECT_EQ(points[1], Point(std::numeric_limits<float>::max(),
2926  std::numeric_limits<float>::lowest()));
2927  EXPECT_EQ(points[2], Point(std::numeric_limits<float>::lowest(),
2928  std::numeric_limits<float>::max()));
2929  EXPECT_EQ(points[3], Point(std::numeric_limits<float>::max(),
2930  std::numeric_limits<float>::max()));
2931  }
2932 }
2933 
2934 TEST(RectTest, RectShift) {
2935  auto r = Rect::MakeLTRB(0, 0, 100, 100);
2936 
2937  EXPECT_EQ(r.Shift(Point(10, 5)), Rect::MakeLTRB(10, 5, 110, 105));
2938  EXPECT_EQ(r.Shift(Point(-10, -5)), Rect::MakeLTRB(-10, -5, 90, 95));
2939 }
2940 
2941 TEST(RectTest, RectGetTransformedPoints) {
2942  Rect r = Rect::MakeXYWH(100, 200, 300, 400);
2943  auto points = r.GetTransformedPoints(Matrix::MakeTranslation({10, 20}));
2944  EXPECT_POINT_NEAR(points[0], Point(110, 220));
2945  EXPECT_POINT_NEAR(points[1], Point(410, 220));
2946  EXPECT_POINT_NEAR(points[2], Point(110, 620));
2947  EXPECT_POINT_NEAR(points[3], Point(410, 620));
2948 }
2949 
2950 TEST(RectTest, RectMakePointBounds) {
2951  {
2952  std::vector<Point> points{{1, 5}, {4, -1}, {0, 6}};
2953  auto r = Rect::MakePointBounds(points.begin(), points.end());
2954  auto expected = Rect::MakeXYWH(0, -1, 4, 7);
2955  EXPECT_TRUE(r.has_value());
2956  if (r.has_value()) {
2957  EXPECT_RECT_NEAR(r.value(), expected);
2958  }
2959  }
2960  {
2961  std::vector<Point> points;
2962  std::optional<Rect> r = Rect::MakePointBounds(points.begin(), points.end());
2963  EXPECT_FALSE(r.has_value());
2964  }
2965 }
2966 
2967 TEST(RectTest, RectGetPositive) {
2968  {
2969  Rect r = Rect::MakeXYWH(100, 200, 300, 400);
2970  auto actual = r.GetPositive();
2971  EXPECT_RECT_NEAR(r, actual);
2972  }
2973  {
2974  Rect r = Rect::MakeXYWH(100, 200, -100, -100);
2975  auto actual = r.GetPositive();
2976  Rect expected = Rect::MakeXYWH(0, 100, 100, 100);
2977  EXPECT_RECT_NEAR(expected, actual);
2978  }
2979 }
2980 
2981 TEST(RectTest, RectDirections) {
2982  auto r = Rect::MakeLTRB(1, 2, 3, 4);
2983 
2984  EXPECT_EQ(r.GetLeft(), 1);
2985  EXPECT_EQ(r.GetTop(), 2);
2986  EXPECT_EQ(r.GetRight(), 3);
2987  EXPECT_EQ(r.GetBottom(), 4);
2988 
2989  EXPECT_POINT_NEAR(r.GetLeftTop(), Point(1, 2));
2990  EXPECT_POINT_NEAR(r.GetRightTop(), Point(3, 2));
2991  EXPECT_POINT_NEAR(r.GetLeftBottom(), Point(1, 4));
2992  EXPECT_POINT_NEAR(r.GetRightBottom(), Point(3, 4));
2993 }
2994 
2995 TEST(RectTest, RectProject) {
2996  {
2997  auto r = Rect::MakeLTRB(-100, -100, 100, 100);
2998  auto actual = r.Project(r);
2999  auto expected = Rect::MakeLTRB(0, 0, 1, 1);
3000  EXPECT_RECT_NEAR(expected, actual);
3001  }
3002  {
3003  auto r = Rect::MakeLTRB(-100, -100, 100, 100);
3004  auto actual = r.Project(Rect::MakeLTRB(0, 0, 100, 100));
3005  auto expected = Rect::MakeLTRB(0.5, 0.5, 1, 1);
3006  EXPECT_RECT_NEAR(expected, actual);
3007  }
3008 }
3009 
3010 TEST(RectTest, RectRoundOut) {
3011  {
3012  auto r = Rect::MakeLTRB(-100, -200, 300, 400);
3013  EXPECT_EQ(Rect::RoundOut(r), r);
3014  }
3015  {
3016  auto r = Rect::MakeLTRB(-100.1, -200.1, 300.1, 400.1);
3017  EXPECT_EQ(Rect::RoundOut(r), Rect::MakeLTRB(-101, -201, 301, 401));
3018  }
3019 }
3020 
3021 TEST(RectTest, IRectRoundOut) {
3022  {
3023  auto r = Rect::MakeLTRB(-100, -200, 300, 400);
3024  auto ir = IRect::MakeLTRB(-100, -200, 300, 400);
3025  EXPECT_EQ(IRect::RoundOut(r), ir);
3026  }
3027  {
3028  auto r = Rect::MakeLTRB(-100.1, -200.1, 300.1, 400.1);
3029  auto ir = IRect::MakeLTRB(-101, -201, 301, 401);
3030  EXPECT_EQ(IRect::RoundOut(r), ir);
3031  }
3032 }
3033 
3034 TEST(RectTest, RectRound) {
3035  {
3036  auto r = Rect::MakeLTRB(-100, -200, 300, 400);
3037  EXPECT_EQ(Rect::Round(r), r);
3038  }
3039  {
3040  auto r = Rect::MakeLTRB(-100.4, -200.4, 300.4, 400.4);
3041  EXPECT_EQ(Rect::Round(r), Rect::MakeLTRB(-100, -200, 300, 400));
3042  }
3043  {
3044  auto r = Rect::MakeLTRB(-100.5, -200.5, 300.5, 400.5);
3045  EXPECT_EQ(Rect::Round(r), Rect::MakeLTRB(-101, -201, 301, 401));
3046  }
3047 }
3048 
3049 TEST(RectTest, IRectRound) {
3050  {
3051  auto r = Rect::MakeLTRB(-100, -200, 300, 400);
3052  auto ir = IRect::MakeLTRB(-100, -200, 300, 400);
3053  EXPECT_EQ(IRect::Round(r), ir);
3054  }
3055  {
3056  auto r = Rect::MakeLTRB(-100.4, -200.4, 300.4, 400.4);
3057  auto ir = IRect::MakeLTRB(-100, -200, 300, 400);
3058  EXPECT_EQ(IRect::Round(r), ir);
3059  }
3060  {
3061  auto r = Rect::MakeLTRB(-100.5, -200.5, 300.5, 400.5);
3062  auto ir = IRect::MakeLTRB(-101, -201, 301, 401);
3063  EXPECT_EQ(IRect::Round(r), ir);
3064  }
3065 }
3066 
3067 TEST(RectTest, TransformAndClipBounds) {
3068  {
3069  // This matrix should clip no corners.
3070  auto matrix = impeller::Matrix::MakeColumn(
3071  // clang-format off
3072  2.0f, 0.0f, 0.0f, 0.0f,
3073  0.0f, 4.0f, 0.0f, 0.0f,
3074  0.0f, 0.0f, 1.0f, 0.0f,
3075  0.0f, 0.0f, 0.0f, 8.0f
3076  // clang-format on
3077  );
3078  Rect src = Rect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3079  // None of these should have a W<0
3080  EXPECT_EQ(matrix.TransformHomogenous(src.GetLeftTop()),
3081  Vector3(200.0f, 400.0f, 8.0f));
3082  EXPECT_EQ(matrix.TransformHomogenous(src.GetRightTop()),
3083  Vector3(400.0f, 400.0f, 8.0f));
3084  EXPECT_EQ(matrix.TransformHomogenous(src.GetLeftBottom()),
3085  Vector3(200.0f, 800.0f, 8.0f));
3086  EXPECT_EQ(matrix.TransformHomogenous(src.GetRightBottom()),
3087  Vector3(400.0f, 800.0f, 8.0f));
3088 
3089  Rect expect = Rect::MakeLTRB(25.0f, 50.0f, 50.0f, 100.0f);
3090  EXPECT_FALSE(src.TransformAndClipBounds(matrix).IsEmpty());
3091  EXPECT_EQ(src.TransformAndClipBounds(matrix), expect);
3092  }
3093 
3094  {
3095  // This matrix should clip one corner.
3096  auto matrix = impeller::Matrix::MakeColumn(
3097  // clang-format off
3098  2.0f, 0.0f, 0.0f, -0.01f,
3099  0.0f, 2.0f, 0.0f, -0.006f,
3100  0.0f, 0.0f, 1.0f, 0.0f,
3101  0.0f, 0.0f, 0.0f, 3.0f
3102  // clang-format on
3103  );
3104  Rect src = Rect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3105  // Exactly one of these should have a W<0
3106  EXPECT_VECTOR3_NEAR(matrix.TransformHomogenous(src.GetLeftTop()),
3107  Vector3(200.0f, 200.0f, 1.4f));
3108  EXPECT_VECTOR3_NEAR(matrix.TransformHomogenous(src.GetRightTop()),
3109  Vector3(400.0f, 200.0f, 0.4f));
3110  EXPECT_VECTOR3_NEAR(matrix.TransformHomogenous(src.GetLeftBottom()),
3111  Vector3(200.0f, 400.0f, 0.8f));
3112  EXPECT_VECTOR3_NEAR(matrix.TransformHomogenous(src.GetRightBottom()),
3113  Vector3(400.0f, 400.0f, -0.2f));
3114 
3115  Rect expect = Rect::MakeLTRB(142.85715f, 142.85715f, 6553600.f, 6553600.f);
3116  EXPECT_FALSE(src.TransformAndClipBounds(matrix).IsEmpty());
3117  EXPECT_RECT_NEAR(src.TransformAndClipBounds(matrix), expect);
3118  }
3119 
3120  {
3121  // This matrix should clip two corners.
3122  auto matrix = impeller::Matrix::MakeColumn(
3123  // clang-format off
3124  2.0f, 0.0f, 0.0f, -.015f,
3125  0.0f, 2.0f, 0.0f, -.006f,
3126  0.0f, 0.0f, 1.0f, 0.0f,
3127  0.0f, 0.0f, 0.0f, 3.0f
3128  // clang-format on
3129  );
3130  Rect src = Rect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3131  // Exactly two of these should have a W<0
3132  EXPECT_VECTOR3_NEAR(matrix.TransformHomogenous(src.GetLeftTop()),
3133  Vector3(200.0f, 200.0f, 0.9f));
3134  EXPECT_VECTOR3_NEAR(matrix.TransformHomogenous(src.GetRightTop()),
3135  Vector3(400.0f, 200.0f, -0.6f));
3136  EXPECT_VECTOR3_NEAR(matrix.TransformHomogenous(src.GetLeftBottom()),
3137  Vector3(200.0f, 400.0f, 0.3f));
3138  EXPECT_VECTOR3_NEAR(matrix.TransformHomogenous(src.GetRightBottom()),
3139  Vector3(400.0f, 400.0f, -1.2f));
3140 
3141  Rect expect = Rect::MakeLTRB(222.2222f, 222.2222f, 5898373.f, 6553600.f);
3142  EXPECT_FALSE(src.TransformAndClipBounds(matrix).IsEmpty());
3143  EXPECT_RECT_NEAR(src.TransformAndClipBounds(matrix), expect);
3144  }
3145 
3146  {
3147  // This matrix should clip three corners.
3148  auto matrix = impeller::Matrix::MakeColumn(
3149  // clang-format off
3150  2.0f, 0.0f, 0.0f, -.02f,
3151  0.0f, 2.0f, 0.0f, -.006f,
3152  0.0f, 0.0f, 1.0f, 0.0f,
3153  0.0f, 0.0f, 0.0f, 3.0f
3154  // clang-format on
3155  );
3156  Rect src = Rect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3157  // Exactly three of these should have a W<0
3158  EXPECT_VECTOR3_NEAR(matrix.TransformHomogenous(src.GetLeftTop()),
3159  Vector3(200.0f, 200.0f, 0.4f));
3160  EXPECT_VECTOR3_NEAR(matrix.TransformHomogenous(src.GetRightTop()),
3161  Vector3(400.0f, 200.0f, -1.6f));
3162  EXPECT_VECTOR3_NEAR(matrix.TransformHomogenous(src.GetLeftBottom()),
3163  Vector3(200.0f, 400.0f, -0.2f));
3164  EXPECT_VECTOR3_NEAR(matrix.TransformHomogenous(src.GetRightBottom()),
3165  Vector3(400.0f, 400.0f, -2.2f));
3166 
3167  Rect expect = Rect::MakeLTRB(499.99988f, 499.99988f, 5898340.f, 4369400.f);
3168  EXPECT_FALSE(src.TransformAndClipBounds(matrix).IsEmpty());
3169  EXPECT_RECT_NEAR(src.TransformAndClipBounds(matrix), expect);
3170  }
3171 
3172  {
3173  // This matrix should clip all four corners.
3174  auto matrix = impeller::Matrix::MakeColumn(
3175  // clang-format off
3176  2.0f, 0.0f, 0.0f, -.025f,
3177  0.0f, 2.0f, 0.0f, -.006f,
3178  0.0f, 0.0f, 1.0f, 0.0f,
3179  0.0f, 0.0f, 0.0f, 3.0f
3180  // clang-format on
3181  );
3182  Rect src = Rect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3183  // All of these should have a W<0
3184  EXPECT_VECTOR3_NEAR(matrix.TransformHomogenous(src.GetLeftTop()),
3185  Vector3(200.0f, 200.0f, -0.1f));
3186  EXPECT_VECTOR3_NEAR(matrix.TransformHomogenous(src.GetRightTop()),
3187  Vector3(400.0f, 200.0f, -2.6f));
3188  EXPECT_VECTOR3_NEAR(matrix.TransformHomogenous(src.GetLeftBottom()),
3189  Vector3(200.0f, 400.0f, -0.7f));
3190  EXPECT_VECTOR3_NEAR(matrix.TransformHomogenous(src.GetRightBottom()),
3191  Vector3(400.0f, 400.0f, -3.2f));
3192 
3193  EXPECT_TRUE(src.TransformAndClipBounds(matrix).IsEmpty());
3194  }
3195 }
3196 
3197 } // namespace testing
3198 } // namespace impeller
impeller::testing::swap_nan
static constexpr Rect swap_nan(const Rect &rect, int index)
Definition: rect_unittests.cc:1295
impeller::TPoint::y
Type y
Definition: point.h:31
impeller::Scalar
float Scalar
Definition: scalar.h:18
geometry_asserts.h
impeller::TRect< Scalar >::MakeXYWH
constexpr static TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition: rect.h:136
impeller::kEhCloseEnough
constexpr float kEhCloseEnough
Definition: constants.h:56
impeller::TRect::GetLeftTop
constexpr TPoint< T > GetLeftTop() const
Definition: rect.h:349
impeller::TRect::Intersection
constexpr std::optional< TRect > Intersection(const TRect &o) const
Definition: rect.h:519
impeller::testing::TEST
TEST(AiksCanvasTest, EmptyCullRect)
Definition: canvas_unittests.cc:18
EXPECT_POINT_NEAR
#define EXPECT_POINT_NEAR(a, b)
Definition: geometry_asserts.h:205
impeller::TRect::CutoutOrEmpty
constexpr TRect CutoutOrEmpty(const TRect &o) const
Definition: rect.h:584
impeller::testing::flip_lrtb
static constexpr R flip_lrtb(R rect)
Definition: rect_unittests.cc:1291
impeller::TRect< Scalar >::Round
Round(const TRect< U > &r)
Definition: rect.h:674
impeller::TRect::GetX
constexpr Type GetX() const
Returns the X coordinate of the upper left corner, equivalent to |GetOrigin().x|.
Definition: rect.h:323
impeller::TRect::GetHeight
constexpr Type GetHeight() const
Returns the height of the rectangle, equivalent to |GetSize().height|.
Definition: rect.h:337
impeller::Matrix::MakeTranslation
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition: matrix.h:95
impeller::TRect::GetOrigin
constexpr TPoint< Type > GetOrigin() const
Returns the upper left corner of the rectangle as specified by the left/top or x/y values when it was...
Definition: rect.h:310
impeller::TRect::GetRightTop
constexpr TPoint< T > GetRightTop() const
Definition: rect.h:353
EXPECT_RECT_NEAR
#define EXPECT_RECT_NEAR(a, b)
Definition: geometry_asserts.h:203
impeller::TRect::IntersectsWithRect
constexpr bool IntersectsWithRect(const TRect &o) const
Definition: rect.h:533
impeller::TRect::GetPoints
constexpr std::array< TPoint< T >, 4 > GetPoints() const
Get the points that represent the 4 corners of this rectangle in a Z order that is compatible with tr...
Definition: rect.h:405
impeller::TRect< Scalar >::MakePointBounds
constexpr static std::optional< TRect > MakePointBounds(const U &value)
Definition: rect.h:151
impeller::TRect::ContainsInclusive
constexpr bool ContainsInclusive(const TPoint< Type > &p) const
Returns true iff the provided point |p| is inside the closed-range interior of this rectangle.
Definition: rect.h:240
impeller::TRect::IsEmpty
constexpr bool IsEmpty() const
Returns true if either of the width or height are 0, negative, or NaN.
Definition: rect.h:287
impeller::TRect< Scalar >::RoundOut
RoundOut(const TRect< U > &r)
Definition: rect.h:666
impeller::TSize< Scalar >
impeller::Point
TPoint< Scalar > Point
Definition: point.h:322
impeller::Quad
std::array< Point, 4 > Quad
Definition: point.h:327
impeller::TRect::TransformAndClipBounds
constexpr TRect TransformAndClipBounds(const Matrix &transform) const
Creates a new bounding box that contains this transformed rectangle, clipped against the near clippin...
Definition: rect.h:429
impeller::TRect::GetLeft
constexpr auto GetLeft() const
Definition: rect.h:341
impeller::testing::flip_lr
static constexpr R flip_lr(R rect)
Definition: rect_unittests.cc:1279
impeller::TRect::GetTransformedPoints
constexpr std::array< TPoint< T >, 4 > GetTransformedPoints(const Matrix &transform) const
Definition: rect.h:417
EXPECT_VECTOR3_NEAR
#define EXPECT_VECTOR3_NEAR(a, b)
Definition: geometry_asserts.h:206
impeller::TRect::GetWidth
constexpr Type GetWidth() const
Returns the width of the rectangle, equivalent to |GetSize().width|.
Definition: rect.h:331
impeller::TRect::GetLeftBottom
constexpr TPoint< T > GetLeftBottom() const
Definition: rect.h:357
impeller::TRect< Scalar >::MakeOriginSize
constexpr static TRect MakeOriginSize(const TPoint< Type > &origin, const TSize< Type > &size)
Definition: rect.h:140
impeller::Matrix::MakeColumn
static constexpr Matrix MakeColumn(Scalar m0, Scalar m1, Scalar m2, Scalar m3, Scalar m4, Scalar m5, Scalar m6, Scalar m7, Scalar m8, Scalar m9, Scalar m10, Scalar m11, Scalar m12, Scalar m13, Scalar m14, Scalar m15)
Definition: matrix.h:69
impeller::TRect::Scale
constexpr TRect Scale(Type scale) const
Definition: rect.h:192
impeller::Rect
TRect< Scalar > Rect
Definition: rect.h:769
impeller::TRect::Contains
constexpr bool Contains(const TPoint< Type > &p) const
Returns true iff the provided point |p| is inside the half-open interior of this rectangle.
Definition: rect.h:221
impeller::TPoint::x
Type x
Definition: point.h:30
impeller::TRect::IsFinite
IsFinite() const
Returns true if all of the fields of this floating point rectangle are finite.
Definition: rect.h:278
impeller::TRect::Cutout
constexpr std::optional< TRect< T > > Cutout(const TRect &o) const
Returns the new boundary rectangle that would result from this rectangle being cut out by the specifi...
Definition: rect.h:544
impeller::TRect::GetSize
constexpr TSize< Type > GetSize() const
Returns the size of the rectangle which may be negative in either width or height and may have been c...
Definition: rect.h:317
impeller::TRect::GetRight
constexpr auto GetRight() const
Definition: rect.h:345
RectNear
inline ::testing::AssertionResult RectNear(impeller::Rect a, impeller::Rect b)
Definition: geometry_asserts.h:89
impeller::TRect< Scalar >::MakeSize
constexpr static TRect MakeSize(const TSize< U > &size)
Definition: rect.h:146
impeller::IPoint
TPoint< int64_t > IPoint
Definition: point.h:323
rect.h
impeller::TPoint< Scalar >
impeller::TRect< Scalar >::MakeMaximum
constexpr static TRect MakeMaximum()
Definition: rect.h:174
impeller::saturated::b
SI b
Definition: saturated_math.h:87
scale
const Scalar scale
Definition: stroke_path_geometry.cc:308
impeller::TRect::Union
constexpr TRect Union(const TRect &o) const
Definition: rect.h:504
impeller::TRect::GetBottom
constexpr auto GetBottom() const
Definition: rect.h:347
impeller::IRect
IRect64 IRect
Definition: rect.h:772
impeller::TRect< Scalar >::MakeLTRB
constexpr static TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition: rect.h:129
impeller::TRect::GetPositive
constexpr TRect GetPositive() const
Get a version of this rectangle that has a non-negative size.
Definition: rect.h:389
impeller::TRect::GetRightBottom
constexpr TPoint< T > GetRightBottom() const
Definition: rect.h:361
impeller::testing::flip_tb
static constexpr R flip_tb(R rect)
Definition: rect_unittests.cc:1285
impeller::TRect::GetY
constexpr Type GetY() const
Returns the Y coordinate of the upper left corner, equivalent to |GetOrigin().y|.
Definition: rect.h:327
impeller
Definition: aiks_blend_unittests.cc:18
impeller::TRect::GetXYWH
constexpr std::array< T, 4 > GetXYWH() const
Get the x, y coordinates of the origin and the width and height of the rectangle in an array.
Definition: rect.h:384
impeller::Matrix::MakeScale
static constexpr Matrix MakeScale(const Vector3 &s)
Definition: matrix.h:104
impeller::TRect::GetTop
constexpr auto GetTop() const
Definition: rect.h:343
impeller::TRect
Definition: rect.h:122
impeller::Vector3
Definition: vector.h:20