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