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