Flutter Impeller
round_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(RoundRectTest, EmptyDeclaration) {
15  RoundRect round_rect;
16 
17  EXPECT_TRUE(round_rect.IsEmpty());
18  EXPECT_FALSE(round_rect.IsRect());
19  EXPECT_FALSE(round_rect.IsOval());
20  EXPECT_TRUE(round_rect.IsFinite());
21  EXPECT_TRUE(round_rect.GetBounds().IsEmpty());
22  EXPECT_EQ(round_rect.GetBounds(), Rect());
23  EXPECT_EQ(round_rect.GetBounds().GetLeft(), 0.0f);
24  EXPECT_EQ(round_rect.GetBounds().GetTop(), 0.0f);
25  EXPECT_EQ(round_rect.GetBounds().GetRight(), 0.0f);
26  EXPECT_EQ(round_rect.GetBounds().GetBottom(), 0.0f);
27  EXPECT_EQ(round_rect.GetRadii().top_left, Size());
28  EXPECT_EQ(round_rect.GetRadii().top_right, Size());
29  EXPECT_EQ(round_rect.GetRadii().bottom_left, Size());
30  EXPECT_EQ(round_rect.GetRadii().bottom_right, Size());
31  EXPECT_EQ(round_rect.GetRadii().top_left.width, 0.0f);
32  EXPECT_EQ(round_rect.GetRadii().top_left.height, 0.0f);
33  EXPECT_EQ(round_rect.GetRadii().top_right.width, 0.0f);
34  EXPECT_EQ(round_rect.GetRadii().top_right.height, 0.0f);
35  EXPECT_EQ(round_rect.GetRadii().bottom_left.width, 0.0f);
36  EXPECT_EQ(round_rect.GetRadii().bottom_left.height, 0.0f);
37  EXPECT_EQ(round_rect.GetRadii().bottom_right.width, 0.0f);
38  EXPECT_EQ(round_rect.GetRadii().bottom_right.height, 0.0f);
39 }
40 
41 TEST(RoundRectTest, DefaultConstructor) {
42  RoundRect round_rect = RoundRect();
43 
44  EXPECT_TRUE(round_rect.IsEmpty());
45  EXPECT_FALSE(round_rect.IsRect());
46  EXPECT_FALSE(round_rect.IsOval());
47  EXPECT_TRUE(round_rect.IsFinite());
48  EXPECT_TRUE(round_rect.GetBounds().IsEmpty());
49  EXPECT_EQ(round_rect.GetBounds(), Rect());
50  EXPECT_EQ(round_rect.GetRadii().top_left, Size());
51  EXPECT_EQ(round_rect.GetRadii().top_right, Size());
52  EXPECT_EQ(round_rect.GetRadii().bottom_left, Size());
53  EXPECT_EQ(round_rect.GetRadii().bottom_right, Size());
54 }
55 
56 TEST(RoundRectTest, EmptyRectConstruction) {
57  RoundRect round_rect =
58  RoundRect::MakeRect(Rect::MakeLTRB(20.0f, 20.0f, 20.0f, 20.0f));
59 
60  EXPECT_TRUE(round_rect.IsEmpty());
61  EXPECT_FALSE(round_rect.IsRect());
62  EXPECT_FALSE(round_rect.IsOval());
63  EXPECT_TRUE(round_rect.IsFinite());
64  EXPECT_TRUE(round_rect.GetBounds().IsEmpty());
65  EXPECT_EQ(round_rect.GetBounds(), Rect::MakeLTRB(20.0f, 20.0f, 20.0f, 20.0f));
66  EXPECT_EQ(round_rect.GetRadii().top_left, Size());
67  EXPECT_EQ(round_rect.GetRadii().top_right, Size());
68  EXPECT_EQ(round_rect.GetRadii().bottom_left, Size());
69  EXPECT_EQ(round_rect.GetRadii().bottom_right, Size());
70 }
71 
72 TEST(RoundRectTest, RectConstructor) {
73  RoundRect round_rect =
74  RoundRect::MakeRect(Rect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f));
75 
76  EXPECT_FALSE(round_rect.IsEmpty());
77  EXPECT_TRUE(round_rect.IsRect());
78  EXPECT_FALSE(round_rect.IsOval());
79  EXPECT_TRUE(round_rect.IsFinite());
80  EXPECT_FALSE(round_rect.GetBounds().IsEmpty());
81  EXPECT_EQ(round_rect.GetBounds(), Rect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f));
82  EXPECT_EQ(round_rect.GetRadii().top_left, Size());
83  EXPECT_EQ(round_rect.GetRadii().top_right, Size());
84  EXPECT_EQ(round_rect.GetRadii().bottom_left, Size());
85  EXPECT_EQ(round_rect.GetRadii().bottom_right, Size());
86 }
87 
88 TEST(RoundRectTest, InvertedRectConstruction) {
89  RoundRect round_rect =
90  RoundRect::MakeRect(Rect::MakeLTRB(20.0f, 20.0f, 10.0f, 10.0f));
91 
92  EXPECT_FALSE(round_rect.IsEmpty());
93  EXPECT_TRUE(round_rect.IsRect());
94  EXPECT_FALSE(round_rect.IsOval());
95  EXPECT_TRUE(round_rect.IsFinite());
96  EXPECT_FALSE(round_rect.GetBounds().IsEmpty());
97  EXPECT_EQ(round_rect.GetBounds(), Rect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f));
98  EXPECT_EQ(round_rect.GetRadii().top_left, Size());
99  EXPECT_EQ(round_rect.GetRadii().top_right, Size());
100  EXPECT_EQ(round_rect.GetRadii().bottom_left, Size());
101  EXPECT_EQ(round_rect.GetRadii().bottom_right, Size());
102 }
103 
104 TEST(RoundRectTest, EmptyOvalConstruction) {
105  RoundRect round_rect = RoundRect::MakeRectXY(
106  Rect::MakeLTRB(20.0f, 20.0f, 20.0f, 20.0f), 10.0f, 10.0f);
107 
108  EXPECT_TRUE(round_rect.IsEmpty());
109  EXPECT_FALSE(round_rect.IsRect());
110  EXPECT_FALSE(round_rect.IsOval());
111  EXPECT_TRUE(round_rect.IsFinite());
112  EXPECT_TRUE(round_rect.GetBounds().IsEmpty());
113  EXPECT_EQ(round_rect.GetBounds(), Rect::MakeLTRB(20.0f, 20.0f, 20.0f, 20.0f));
114  EXPECT_EQ(round_rect.GetRadii().top_left, Size());
115  EXPECT_EQ(round_rect.GetRadii().top_right, Size());
116  EXPECT_EQ(round_rect.GetRadii().bottom_left, Size());
117  EXPECT_EQ(round_rect.GetRadii().bottom_right, Size());
118 }
119 
120 TEST(RoundRectTest, OvalConstructor) {
121  RoundRect round_rect =
122  RoundRect::MakeOval(Rect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f));
123 
124  EXPECT_FALSE(round_rect.IsEmpty());
125  EXPECT_FALSE(round_rect.IsRect());
126  EXPECT_TRUE(round_rect.IsOval());
127  EXPECT_TRUE(round_rect.IsFinite());
128  EXPECT_FALSE(round_rect.GetBounds().IsEmpty());
129  EXPECT_EQ(round_rect.GetBounds(), Rect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f));
130  EXPECT_EQ(round_rect.GetRadii().top_left, Size(5.0f, 5.0f));
131  EXPECT_EQ(round_rect.GetRadii().top_right, Size(5.0f, 5.0f));
132  EXPECT_EQ(round_rect.GetRadii().bottom_left, Size(5.0f, 5.0f));
133  EXPECT_EQ(round_rect.GetRadii().bottom_right, Size(5.0f, 5.0f));
134 }
135 
136 TEST(RoundRectTest, InvertedOvalConstruction) {
137  RoundRect round_rect = RoundRect::MakeRectXY(
138  Rect::MakeLTRB(20.0f, 20.0f, 10.0f, 10.0f), 10.0f, 10.0f);
139 
140  EXPECT_FALSE(round_rect.IsEmpty());
141  EXPECT_FALSE(round_rect.IsRect());
142  EXPECT_TRUE(round_rect.IsOval());
143  EXPECT_TRUE(round_rect.IsFinite());
144  EXPECT_FALSE(round_rect.GetBounds().IsEmpty());
145  EXPECT_EQ(round_rect.GetBounds(), Rect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f));
146  EXPECT_EQ(round_rect.GetRadii().top_left, Size(5.0f, 5.0f));
147  EXPECT_EQ(round_rect.GetRadii().top_right, Size(5.0f, 5.0f));
148  EXPECT_EQ(round_rect.GetRadii().bottom_left, Size(5.0f, 5.0f));
149  EXPECT_EQ(round_rect.GetRadii().bottom_right, Size(5.0f, 5.0f));
150 }
151 
152 TEST(RoundRectTest, RectRadiusConstructor) {
154  Rect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f), 2.0f);
155 
156  EXPECT_FALSE(round_rect.IsEmpty());
157  EXPECT_FALSE(round_rect.IsRect());
158  EXPECT_FALSE(round_rect.IsOval());
159  EXPECT_TRUE(round_rect.IsFinite());
160  EXPECT_FALSE(round_rect.GetBounds().IsEmpty());
161  EXPECT_EQ(round_rect.GetBounds(), Rect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f));
162  EXPECT_EQ(round_rect.GetRadii().top_left, Size(2.0f, 2.0f));
163  EXPECT_EQ(round_rect.GetRadii().top_right, Size(2.0f, 2.0f));
164  EXPECT_EQ(round_rect.GetRadii().bottom_left, Size(2.0f, 2.0f));
165  EXPECT_EQ(round_rect.GetRadii().bottom_right, Size(2.0f, 2.0f));
166 }
167 
168 TEST(RoundRectTest, RectXYConstructor) {
169  RoundRect round_rect = RoundRect::MakeRectXY(
170  Rect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f), 2.0f, 3.0f);
171 
172  EXPECT_FALSE(round_rect.IsEmpty());
173  EXPECT_FALSE(round_rect.IsRect());
174  EXPECT_FALSE(round_rect.IsOval());
175  EXPECT_TRUE(round_rect.IsFinite());
176  EXPECT_FALSE(round_rect.GetBounds().IsEmpty());
177  EXPECT_EQ(round_rect.GetBounds(), Rect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f));
178  EXPECT_EQ(round_rect.GetRadii().top_left, Size(2.0f, 3.0f));
179  EXPECT_EQ(round_rect.GetRadii().top_right, Size(2.0f, 3.0f));
180  EXPECT_EQ(round_rect.GetRadii().bottom_left, Size(2.0f, 3.0f));
181  EXPECT_EQ(round_rect.GetRadii().bottom_right, Size(2.0f, 3.0f));
182 }
183 
184 TEST(RoundRectTest, RectSizeConstructor) {
185  RoundRect round_rect = RoundRect::MakeRectXY(
186  Rect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f), Size(2.0f, 3.0f));
187 
188  EXPECT_FALSE(round_rect.IsEmpty());
189  EXPECT_FALSE(round_rect.IsRect());
190  EXPECT_FALSE(round_rect.IsOval());
191  EXPECT_TRUE(round_rect.IsFinite());
192  EXPECT_FALSE(round_rect.GetBounds().IsEmpty());
193  EXPECT_EQ(round_rect.GetBounds(), Rect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f));
194  EXPECT_EQ(round_rect.GetRadii().top_left, Size(2.0f, 3.0f));
195  EXPECT_EQ(round_rect.GetRadii().top_right, Size(2.0f, 3.0f));
196  EXPECT_EQ(round_rect.GetRadii().bottom_left, Size(2.0f, 3.0f));
197  EXPECT_EQ(round_rect.GetRadii().bottom_right, Size(2.0f, 3.0f));
198 }
199 
200 TEST(RoundRectTest, RectRadiiConstructor) {
201  RoundRect round_rect =
202  RoundRect::MakeRectRadii(Rect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f),
203  {
204  .top_left = Size(1.0, 1.5),
205  .top_right = Size(2.0, 2.5f),
206  .bottom_left = Size(3.0, 3.5f),
207  .bottom_right = Size(4.0, 4.5f),
208  });
209 
210  EXPECT_FALSE(round_rect.IsEmpty());
211  EXPECT_FALSE(round_rect.IsRect());
212  EXPECT_FALSE(round_rect.IsOval());
213  EXPECT_TRUE(round_rect.IsFinite());
214  EXPECT_FALSE(round_rect.GetBounds().IsEmpty());
215  EXPECT_EQ(round_rect.GetBounds(), Rect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f));
216  EXPECT_EQ(round_rect.GetRadii().top_left, Size(1.0f, 1.5f));
217  EXPECT_EQ(round_rect.GetRadii().top_right, Size(2.0f, 2.5f));
218  EXPECT_EQ(round_rect.GetRadii().bottom_left, Size(3.0f, 3.5f));
219  EXPECT_EQ(round_rect.GetRadii().bottom_right, Size(4.0f, 4.5f));
220 }
221 
222 TEST(RoundRectTest, RectRadiiOverflowWidthConstructor) {
223  RoundRect round_rect =
224  RoundRect::MakeRectRadii(Rect::MakeXYWH(10.0f, 10.0f, 6.0f, 30.0f),
225  {
226  .top_left = Size(1.0f, 2.0f),
227  .top_right = Size(3.0f, 4.0f),
228  .bottom_left = Size(5.0f, 6.0f),
229  .bottom_right = Size(7.0f, 8.0f),
230  });
231  // Largest sum of paired radii widths is the bottom edge which sums to 12
232  // Rect is only 6 wide so all radii are scaled by half
233  // Rect is 30 tall so no scaling should happen due to radii heights
234 
235  EXPECT_FALSE(round_rect.IsEmpty());
236  EXPECT_FALSE(round_rect.IsRect());
237  EXPECT_FALSE(round_rect.IsOval());
238  EXPECT_TRUE(round_rect.IsFinite());
239  EXPECT_FALSE(round_rect.GetBounds().IsEmpty());
240  EXPECT_EQ(round_rect.GetBounds(), Rect::MakeLTRB(10.0f, 10.0f, 16.0f, 40.0f));
241  EXPECT_EQ(round_rect.GetRadii().top_left, Size(0.5f, 1.0f));
242  EXPECT_EQ(round_rect.GetRadii().top_right, Size(1.5f, 2.0f));
243  EXPECT_EQ(round_rect.GetRadii().bottom_left, Size(2.5f, 3.0f));
244  EXPECT_EQ(round_rect.GetRadii().bottom_right, Size(3.5f, 4.0f));
245 }
246 
247 TEST(RoundRectTest, RectRadiiOverflowHeightConstructor) {
248  RoundRect round_rect =
249  RoundRect::MakeRectRadii(Rect::MakeXYWH(10.0f, 10.0f, 30.0f, 6.0f),
250  {
251  .top_left = Size(1.0f, 2.0f),
252  .top_right = Size(3.0f, 4.0f),
253  .bottom_left = Size(5.0f, 6.0f),
254  .bottom_right = Size(7.0f, 8.0f),
255  });
256  // Largest sum of paired radii heights is the right edge which sums to 12
257  // Rect is only 6 tall so all radii are scaled by half
258  // Rect is 30 wide so no scaling should happen due to radii widths
259 
260  EXPECT_FALSE(round_rect.IsEmpty());
261  EXPECT_FALSE(round_rect.IsRect());
262  EXPECT_FALSE(round_rect.IsOval());
263  EXPECT_TRUE(round_rect.IsFinite());
264  EXPECT_FALSE(round_rect.GetBounds().IsEmpty());
265  EXPECT_EQ(round_rect.GetBounds(), Rect::MakeLTRB(10.0f, 10.0f, 40.0f, 16.0f));
266  EXPECT_EQ(round_rect.GetRadii().top_left, Size(0.5f, 1.0f));
267  EXPECT_EQ(round_rect.GetRadii().top_right, Size(1.5f, 2.0f));
268  EXPECT_EQ(round_rect.GetRadii().bottom_left, Size(2.5f, 3.0f));
269  EXPECT_EQ(round_rect.GetRadii().bottom_right, Size(3.5f, 4.0f));
270 }
271 
272 TEST(RoundRectTest, Shift) {
273  RoundRect round_rect =
274  RoundRect::MakeRectRadii(Rect::MakeXYWH(10.0f, 10.0f, 30.0f, 30.0f),
275  {
276  .top_left = Size(1.0f, 2.0f),
277  .top_right = Size(3.0f, 4.0f),
278  .bottom_left = Size(5.0f, 6.0f),
279  .bottom_right = Size(7.0f, 8.0f),
280  });
281  RoundRect shifted = round_rect.Shift(5.0, 6.0);
282 
283  EXPECT_FALSE(shifted.IsEmpty());
284  EXPECT_FALSE(shifted.IsRect());
285  EXPECT_FALSE(shifted.IsOval());
286  EXPECT_TRUE(shifted.IsFinite());
287  EXPECT_FALSE(shifted.GetBounds().IsEmpty());
288  EXPECT_EQ(shifted.GetBounds(), Rect::MakeLTRB(15.0f, 16.0f, 45.0f, 46.0f));
289  EXPECT_EQ(shifted.GetRadii().top_left, Size(1.0f, 2.0f));
290  EXPECT_EQ(shifted.GetRadii().top_right, Size(3.0f, 4.0f));
291  EXPECT_EQ(shifted.GetRadii().bottom_left, Size(5.0f, 6.0f));
292  EXPECT_EQ(shifted.GetRadii().bottom_right, Size(7.0f, 8.0f));
293 
294  EXPECT_EQ(shifted,
295  RoundRect::MakeRectRadii(Rect::MakeXYWH(15.0f, 16.0f, 30.0f, 30.0f),
296  {
297  .top_left = Size(1.0f, 2.0f),
298  .top_right = Size(3.0f, 4.0f),
299  .bottom_left = Size(5.0f, 6.0f),
300  .bottom_right = Size(7.0f, 8.0f),
301  }));
302 }
303 
304 TEST(RoundRectTest, ExpandScalar) {
305  RoundRect round_rect =
306  RoundRect::MakeRectRadii(Rect::MakeXYWH(10.0f, 10.0f, 30.0f, 30.0f),
307  {
308  .top_left = Size(1.0f, 2.0f),
309  .top_right = Size(3.0f, 4.0f),
310  .bottom_left = Size(5.0f, 6.0f),
311  .bottom_right = Size(7.0f, 8.0f),
312  });
313  RoundRect expanded = round_rect.Expand(5.0);
314 
315  EXPECT_FALSE(expanded.IsEmpty());
316  EXPECT_FALSE(expanded.IsRect());
317  EXPECT_FALSE(expanded.IsOval());
318  EXPECT_TRUE(expanded.IsFinite());
319  EXPECT_FALSE(expanded.GetBounds().IsEmpty());
320  EXPECT_EQ(expanded.GetBounds(), Rect::MakeLTRB(5.0f, 5.0f, 45.0f, 45.0f));
321  EXPECT_EQ(expanded.GetRadii().top_left, Size(1.0f, 2.0f));
322  EXPECT_EQ(expanded.GetRadii().top_right, Size(3.0f, 4.0f));
323  EXPECT_EQ(expanded.GetRadii().bottom_left, Size(5.0f, 6.0f));
324  EXPECT_EQ(expanded.GetRadii().bottom_right, Size(7.0f, 8.0f));
325 
326  EXPECT_EQ(expanded,
327  RoundRect::MakeRectRadii(Rect::MakeXYWH(5.0f, 5.0f, 40.0f, 40.0f),
328  {
329  .top_left = Size(1.0f, 2.0f),
330  .top_right = Size(3.0f, 4.0f),
331  .bottom_left = Size(5.0f, 6.0f),
332  .bottom_right = Size(7.0f, 8.0f),
333  }));
334 }
335 
336 TEST(RoundRectTest, ExpandTwoScalars) {
337  RoundRect round_rect =
338  RoundRect::MakeRectRadii(Rect::MakeXYWH(10.0f, 10.0f, 30.0f, 30.0f),
339  {
340  .top_left = Size(1.0f, 2.0f),
341  .top_right = Size(3.0f, 4.0f),
342  .bottom_left = Size(5.0f, 6.0f),
343  .bottom_right = Size(7.0f, 8.0f),
344  });
345  RoundRect expanded = round_rect.Expand(5.0, 6.0);
346 
347  EXPECT_FALSE(expanded.IsEmpty());
348  EXPECT_FALSE(expanded.IsRect());
349  EXPECT_FALSE(expanded.IsOval());
350  EXPECT_TRUE(expanded.IsFinite());
351  EXPECT_FALSE(expanded.GetBounds().IsEmpty());
352  EXPECT_EQ(expanded.GetBounds(), Rect::MakeLTRB(5.0f, 4.0f, 45.0f, 46.0f));
353  EXPECT_EQ(expanded.GetRadii().top_left, Size(1.0f, 2.0f));
354  EXPECT_EQ(expanded.GetRadii().top_right, Size(3.0f, 4.0f));
355  EXPECT_EQ(expanded.GetRadii().bottom_left, Size(5.0f, 6.0f));
356  EXPECT_EQ(expanded.GetRadii().bottom_right, Size(7.0f, 8.0f));
357 
358  EXPECT_EQ(expanded,
359  RoundRect::MakeRectRadii(Rect::MakeXYWH(5.0f, 4.0f, 40.0f, 42.0f),
360  {
361  .top_left = Size(1.0f, 2.0f),
362  .top_right = Size(3.0f, 4.0f),
363  .bottom_left = Size(5.0f, 6.0f),
364  .bottom_right = Size(7.0f, 8.0f),
365  }));
366 }
367 
368 TEST(RoundRectTest, ExpandFourScalars) {
369  RoundRect round_rect =
370  RoundRect::MakeRectRadii(Rect::MakeXYWH(10.0f, 10.0f, 30.0f, 30.0f),
371  {
372  .top_left = Size(1.0f, 2.0f),
373  .top_right = Size(3.0f, 4.0f),
374  .bottom_left = Size(5.0f, 6.0f),
375  .bottom_right = Size(7.0f, 8.0f),
376  });
377  RoundRect expanded = round_rect.Expand(5.0, 6.0, 7.0, 8.0);
378 
379  EXPECT_FALSE(expanded.IsEmpty());
380  EXPECT_FALSE(expanded.IsRect());
381  EXPECT_FALSE(expanded.IsOval());
382  EXPECT_TRUE(expanded.IsFinite());
383  EXPECT_FALSE(expanded.GetBounds().IsEmpty());
384  EXPECT_EQ(expanded.GetBounds(), Rect::MakeLTRB(5.0f, 4.0f, 47.0f, 48.0f));
385  EXPECT_EQ(expanded.GetRadii().top_left, Size(1.0f, 2.0f));
386  EXPECT_EQ(expanded.GetRadii().top_right, Size(3.0f, 4.0f));
387  EXPECT_EQ(expanded.GetRadii().bottom_left, Size(5.0f, 6.0f));
388  EXPECT_EQ(expanded.GetRadii().bottom_right, Size(7.0f, 8.0f));
389 
390  EXPECT_EQ(expanded,
391  RoundRect::MakeRectRadii(Rect::MakeXYWH(5.0f, 4.0f, 42.0f, 44.0f),
392  {
393  .top_left = Size(1.0f, 2.0f),
394  .top_right = Size(3.0f, 4.0f),
395  .bottom_left = Size(5.0f, 6.0f),
396  .bottom_right = Size(7.0f, 8.0f),
397  }));
398 }
399 
400 TEST(RoundRectTest, ContractScalar) {
401  RoundRect round_rect =
402  RoundRect::MakeRectRadii(Rect::MakeXYWH(10.0f, 10.0f, 30.0f, 30.0f),
403  {
404  .top_left = Size(1.0f, 2.0f),
405  .top_right = Size(3.0f, 4.0f),
406  .bottom_left = Size(5.0f, 6.0f),
407  .bottom_right = Size(7.0f, 8.0f),
408  });
409  RoundRect expanded = round_rect.Expand(-2.0);
410 
411  EXPECT_FALSE(expanded.IsEmpty());
412  EXPECT_FALSE(expanded.IsRect());
413  EXPECT_FALSE(expanded.IsOval());
414  EXPECT_TRUE(expanded.IsFinite());
415  EXPECT_FALSE(expanded.GetBounds().IsEmpty());
416  EXPECT_EQ(expanded.GetBounds(), Rect::MakeLTRB(12.0f, 12.0f, 38.0f, 38.0f));
417  EXPECT_EQ(expanded.GetRadii().top_left, Size(1.0f, 2.0f));
418  EXPECT_EQ(expanded.GetRadii().top_right, Size(3.0f, 4.0f));
419  EXPECT_EQ(expanded.GetRadii().bottom_left, Size(5.0f, 6.0f));
420  EXPECT_EQ(expanded.GetRadii().bottom_right, Size(7.0f, 8.0f));
421 
422  EXPECT_EQ(expanded,
423  RoundRect::MakeRectRadii(Rect::MakeXYWH(12.0f, 12.0f, 26.0f, 26.0f),
424  {
425  .top_left = Size(1.0f, 2.0f),
426  .top_right = Size(3.0f, 4.0f),
427  .bottom_left = Size(5.0f, 6.0f),
428  .bottom_right = Size(7.0f, 8.0f),
429  }));
430 }
431 
432 TEST(RoundRectTest, ContractTwoScalars) {
433  RoundRect round_rect =
434  RoundRect::MakeRectRadii(Rect::MakeXYWH(10.0f, 10.0f, 30.0f, 30.0f),
435  {
436  .top_left = Size(1.0f, 2.0f),
437  .top_right = Size(3.0f, 4.0f),
438  .bottom_left = Size(5.0f, 6.0f),
439  .bottom_right = Size(7.0f, 8.0f),
440  });
441  RoundRect expanded = round_rect.Expand(-1.0, -2.0);
442 
443  EXPECT_FALSE(expanded.IsEmpty());
444  EXPECT_FALSE(expanded.IsRect());
445  EXPECT_FALSE(expanded.IsOval());
446  EXPECT_TRUE(expanded.IsFinite());
447  EXPECT_FALSE(expanded.GetBounds().IsEmpty());
448  EXPECT_EQ(expanded.GetBounds(), Rect::MakeLTRB(11.0f, 12.0f, 39.0f, 38.0f));
449  EXPECT_EQ(expanded.GetRadii().top_left, Size(1.0f, 2.0f));
450  EXPECT_EQ(expanded.GetRadii().top_right, Size(3.0f, 4.0f));
451  EXPECT_EQ(expanded.GetRadii().bottom_left, Size(5.0f, 6.0f));
452  EXPECT_EQ(expanded.GetRadii().bottom_right, Size(7.0f, 8.0f));
453 
454  EXPECT_EQ(expanded,
455  RoundRect::MakeRectRadii(Rect::MakeXYWH(11.0f, 12.0f, 28.0f, 26.0f),
456  {
457  .top_left = Size(1.0f, 2.0f),
458  .top_right = Size(3.0f, 4.0f),
459  .bottom_left = Size(5.0f, 6.0f),
460  .bottom_right = Size(7.0f, 8.0f),
461  }));
462 }
463 
464 TEST(RoundRectTest, ContractFourScalars) {
465  RoundRect round_rect =
466  RoundRect::MakeRectRadii(Rect::MakeXYWH(10.0f, 10.0f, 30.0f, 30.0f),
467  {
468  .top_left = Size(1.0f, 2.0f),
469  .top_right = Size(3.0f, 4.0f),
470  .bottom_left = Size(5.0f, 6.0f),
471  .bottom_right = Size(7.0f, 8.0f),
472  });
473  RoundRect expanded = round_rect.Expand(-1.0, -1.5, -2.0, -2.5);
474 
475  EXPECT_FALSE(expanded.IsEmpty());
476  EXPECT_FALSE(expanded.IsRect());
477  EXPECT_FALSE(expanded.IsOval());
478  EXPECT_TRUE(expanded.IsFinite());
479  EXPECT_FALSE(expanded.GetBounds().IsEmpty());
480  EXPECT_EQ(expanded.GetBounds(), Rect::MakeLTRB(11.0f, 11.5f, 38.0f, 37.5f));
481  EXPECT_EQ(expanded.GetRadii().top_left, Size(1.0f, 2.0f));
482  EXPECT_EQ(expanded.GetRadii().top_right, Size(3.0f, 4.0f));
483  EXPECT_EQ(expanded.GetRadii().bottom_left, Size(5.0f, 6.0f));
484  EXPECT_EQ(expanded.GetRadii().bottom_right, Size(7.0f, 8.0f));
485 
486  EXPECT_EQ(expanded,
487  RoundRect::MakeRectRadii(Rect::MakeXYWH(11.0f, 11.5f, 27.0f, 26.0f),
488  {
489  .top_left = Size(1.0f, 2.0f),
490  .top_right = Size(3.0f, 4.0f),
491  .bottom_left = Size(5.0f, 6.0f),
492  .bottom_right = Size(7.0f, 8.0f),
493  }));
494 }
495 
496 TEST(RoundRectTest, ContractAndRequireRadiiAdjustment) {
497  RoundRect round_rect =
498  RoundRect::MakeRectRadii(Rect::MakeXYWH(10.0f, 10.0f, 30.0f, 30.0f),
499  {
500  .top_left = Size(1.0f, 2.0f),
501  .top_right = Size(3.0f, 4.0f),
502  .bottom_left = Size(5.0f, 6.0f),
503  .bottom_right = Size(7.0f, 8.0f),
504  });
505  RoundRect expanded = round_rect.Expand(-12.0);
506  // Largest sum of paired radii sizes are the bottom and right edges
507  // both of which sum to 12
508  // Rect was 30x30 reduced by 12 on all sides leaving only 6x6, so all
509  // radii are scaled by half to avoid overflowing the contracted rect
510 
511  EXPECT_FALSE(expanded.IsEmpty());
512  EXPECT_FALSE(expanded.IsRect());
513  EXPECT_FALSE(expanded.IsOval());
514  EXPECT_TRUE(expanded.IsFinite());
515  EXPECT_FALSE(expanded.GetBounds().IsEmpty());
516  EXPECT_EQ(expanded.GetBounds(), Rect::MakeLTRB(22.0f, 22.0f, 28.0f, 28.0f));
517  EXPECT_EQ(expanded.GetRadii().top_left, Size(0.5f, 1.0f));
518  EXPECT_EQ(expanded.GetRadii().top_right, Size(1.5f, 2.0f));
519  EXPECT_EQ(expanded.GetRadii().bottom_left, Size(2.5f, 3.0f));
520  EXPECT_EQ(expanded.GetRadii().bottom_right, Size(3.5f, 4.0f));
521 
522  // In this test, the MakeRectRadii constructor will make the same
523  // adjustment to the radii that the Expand method applied.
524  EXPECT_EQ(expanded,
525  RoundRect::MakeRectRadii(Rect::MakeXYWH(22.0f, 22.0f, 6.0f, 6.0f),
526  {
527  .top_left = Size(1.0f, 2.0f),
528  .top_right = Size(3.0f, 4.0f),
529  .bottom_left = Size(5.0f, 6.0f),
530  .bottom_right = Size(7.0f, 8.0f),
531  }));
532 
533  // In this test, the arguments to the constructor supply the correctly
534  // adjusted radii (though there is no real way to tell other than
535  // the result is the same).
536  EXPECT_EQ(expanded,
537  RoundRect::MakeRectRadii(Rect::MakeXYWH(22.0f, 22.0f, 6.0f, 6.0f),
538  {
539  .top_left = Size(0.5f, 1.0f),
540  .top_right = Size(1.5f, 2.0f),
541  .bottom_left = Size(2.5f, 3.0f),
542  .bottom_right = Size(3.5f, 4.0f),
543  }));
544 }
545 
546 TEST(RoundRectTest, NoCornerRoundRectContains) {
547  Rect bounds = Rect::MakeLTRB(-50.0f, -50.0f, 50.0f, 50.0f);
548  // RRect of bounds with no corners contains corners just barely
549  auto no_corners = RoundRect::MakeRectXY(bounds, 0.0f, 0.0f);
550 
551  EXPECT_TRUE(no_corners.Contains({-50, -50}));
552  // Rectangles have half-in, half-out containment so we need
553  // to be careful about testing containment of right/bottom corners.
554  EXPECT_TRUE(no_corners.Contains({-50, 49.99}));
555  EXPECT_TRUE(no_corners.Contains({49.99, -50}));
556  EXPECT_TRUE(no_corners.Contains({49.99, 49.99}));
557  EXPECT_FALSE(no_corners.Contains({-50.01, -50}));
558  EXPECT_FALSE(no_corners.Contains({-50, -50.01}));
559  EXPECT_FALSE(no_corners.Contains({-50.01, 50}));
560  EXPECT_FALSE(no_corners.Contains({-50, 50.01}));
561  EXPECT_FALSE(no_corners.Contains({50.01, -50}));
562  EXPECT_FALSE(no_corners.Contains({50, -50.01}));
563  EXPECT_FALSE(no_corners.Contains({50.01, 50}));
564  EXPECT_FALSE(no_corners.Contains({50, 50.01}));
565 }
566 
567 TEST(RoundRectTest, TinyCornerRoundRectContains) {
568  Rect bounds = Rect::MakeLTRB(-50.0f, -50.0f, 50.0f, 50.0f);
569  // RRect of bounds with even the tiniest corners does not contain corners
570  auto tiny_corners = RoundRect::MakeRectXY(bounds, 0.01f, 0.01f);
571 
572  EXPECT_FALSE(tiny_corners.Contains({-50, -50}));
573  EXPECT_FALSE(tiny_corners.Contains({-50, 50}));
574  EXPECT_FALSE(tiny_corners.Contains({50, -50}));
575  EXPECT_FALSE(tiny_corners.Contains({50, 50}));
576 }
577 
578 TEST(RoundRectTest, UniformCircularRoundRectContains) {
579  Rect bounds = Rect::MakeLTRB(-50.0f, -50.0f, 50.0f, 50.0f);
580  auto expanded_2_r_2 = RoundRect::MakeRectXY(bounds.Expand(2.0), 2.0f, 2.0f);
581 
582  // Expanded by 2.0 and then with a corner of 2.0 obviously still
583  // contains the corners
584  EXPECT_TRUE(expanded_2_r_2.Contains({-50, -50}));
585  EXPECT_TRUE(expanded_2_r_2.Contains({-50, 50}));
586  EXPECT_TRUE(expanded_2_r_2.Contains({50, -50}));
587  EXPECT_TRUE(expanded_2_r_2.Contains({50, 50}));
588 
589  // Now we try to box in the corner containment to exactly where the
590  // rounded corner of the expanded round rect with radii of 2.0 lies.
591  // The 45-degree diagonal point of a circle of radius 2.0 lies at:
592  //
593  // (2 * sqrt(2) / 2, 2 * sqrt(2) / 2)
594  // (sqrt(2), sqrt(2))
595  //
596  // So we test +/- (50 + sqrt(2) +/- epsilon)
597  const auto coord_out = 50 + kSqrt2 + kEhCloseEnough;
598  const auto coord_in = 50 + kSqrt2 - kEhCloseEnough;
599  // Upper left corner
600  EXPECT_TRUE(expanded_2_r_2.Contains({-coord_in, -coord_in}));
601  EXPECT_FALSE(expanded_2_r_2.Contains({-coord_out, -coord_out}));
602  // Upper right corner
603  EXPECT_TRUE(expanded_2_r_2.Contains({coord_in, -coord_in}));
604  EXPECT_FALSE(expanded_2_r_2.Contains({coord_out, -coord_out}));
605  // Lower left corner
606  EXPECT_TRUE(expanded_2_r_2.Contains({-coord_in, coord_in}));
607  EXPECT_FALSE(expanded_2_r_2.Contains({-coord_out, coord_out}));
608  // Lower right corner
609  EXPECT_TRUE(expanded_2_r_2.Contains({coord_in, coord_in}));
610  EXPECT_FALSE(expanded_2_r_2.Contains({coord_out, coord_out}));
611 }
612 
613 TEST(RoundRectTest, UniformEllipticalRoundRectContains) {
614  Rect bounds = Rect::MakeLTRB(-50.0f, -50.0f, 50.0f, 50.0f);
615  auto expanded_2_r_2 = RoundRect::MakeRectXY(bounds.Expand(2.0), 2.0f, 3.0f);
616 
617  // Expanded by 2.0 and then with a corner of 2x3 should still
618  // contain the corners
619  EXPECT_TRUE(expanded_2_r_2.Contains({-50, -50}));
620  EXPECT_TRUE(expanded_2_r_2.Contains({-50, 50}));
621  EXPECT_TRUE(expanded_2_r_2.Contains({50, -50}));
622  EXPECT_TRUE(expanded_2_r_2.Contains({50, 50}));
623 
624  // Now we try to box in the corner containment to exactly where the
625  // rounded corner of the expanded round rect with radii of 2x3 lies.
626  // The "45-degree diagonal point" of an ellipse of radii 2x3 lies at:
627  //
628  // (2 * sqrt(2) / 2, 3 * sqrt(2) / 2)
629  // (sqrt(2), 3 * sqrt(2) / 2)
630  //
631  // And the center(s) of these corners are at:
632  // (+/-(50 + 2 - 2), +/-(50 + 2 - 3))
633  // = (+/-50, +/-49)
634  const auto x_coord_out = 50 + kSqrt2 + kEhCloseEnough;
635  const auto x_coord_in = 50 + kSqrt2 - kEhCloseEnough;
636  const auto y_coord_out = 49 + 3 * kSqrt2 / 2 + kEhCloseEnough;
637  const auto y_coord_in = 49 + 3 * kSqrt2 / 2 - kEhCloseEnough;
638  // Upper left corner
639  EXPECT_TRUE(expanded_2_r_2.Contains({-x_coord_in, -y_coord_in}));
640  EXPECT_FALSE(expanded_2_r_2.Contains({-x_coord_out, -y_coord_out}));
641  // Upper right corner
642  EXPECT_TRUE(expanded_2_r_2.Contains({x_coord_in, -y_coord_in}));
643  EXPECT_FALSE(expanded_2_r_2.Contains({x_coord_out, -y_coord_out}));
644  // Lower left corner
645  EXPECT_TRUE(expanded_2_r_2.Contains({-x_coord_in, y_coord_in}));
646  EXPECT_FALSE(expanded_2_r_2.Contains({-x_coord_out, y_coord_out}));
647  // Lower right corner
648  EXPECT_TRUE(expanded_2_r_2.Contains({x_coord_in, y_coord_in}));
649  EXPECT_FALSE(expanded_2_r_2.Contains({x_coord_out, y_coord_out}));
650 }
651 
652 TEST(RoundRectTest, DifferingCornersRoundRectContains) {
653  Rect bounds = Rect::MakeLTRB(-50.0f, -50.0f, 50.0f, 50.0f);
654  auto round_rect =
655  RoundRect::MakeRectRadii(bounds, {
656  .top_left = Size(2.0, 3.0),
657  .top_right = Size(4.0, 5.0),
658  .bottom_left = Size(6.0, 7.0),
659  .bottom_right = Size(8.0, 9.0),
660  });
661 
662  // For a corner with radii {A, B}, the "45 degree point" on the
663  // corner curve will be at an offset of:
664  //
665  // (A * sqrt(2) / 2, B * sqrt(2) / 2)
666  //
667  // And the center(s) of these corners are at:
668  //
669  // (+/-(50 - A), +/-(50 - B))
670  auto coord = [](Scalar radius) {
671  return 50 - radius + radius * kSqrt2 / 2.0f - kEhCloseEnough;
672  };
673  auto coord_in = [&coord](Scalar radius) {
674  return coord(radius) - kEhCloseEnough;
675  };
676  auto coord_out = [&coord](Scalar radius) {
677  // For some reason 1 kEhCloseEnough is not enough to put us outside
678  // in some of the cases, so we use 2x the epsilon.
679  return coord(radius) + 2 * kEhCloseEnough;
680  };
681  // Upper left corner (radii = {2.0, 3.0})
682  EXPECT_TRUE(round_rect.Contains({-coord_in(2.0), -coord_in(3.0)}));
683  EXPECT_FALSE(round_rect.Contains({-coord_out(2.0), -coord_out(3.0)}));
684  // Upper right corner (radii = {4.0, 5.0})
685  EXPECT_TRUE(round_rect.Contains({coord_in(4.0), -coord_in(5.0)}));
686  EXPECT_FALSE(round_rect.Contains({coord_out(4.0), -coord_out(5.0)}));
687  // Lower left corner (radii = {6.0, 7.0})
688  EXPECT_TRUE(round_rect.Contains({-coord_in(6.0), coord_in(7.0)}));
689  EXPECT_FALSE(round_rect.Contains({-coord_out(6.0), coord_out(7.0)}));
690  // Lower right corner (radii = {8.0, 9.0})
691  EXPECT_TRUE(round_rect.Contains({coord_in(8.0), coord_in(9.0)}));
692  EXPECT_FALSE(round_rect.Contains({coord_out(8.0), coord_out(9.0)}));
693 }
694 
695 } // namespace testing
696 } // namespace impeller
TEST(AllocationSizeTest, CanCreateTypedAllocations)
float Scalar
Definition: scalar.h:19
constexpr float kEhCloseEnough
Definition: constants.h:57
TSize< Scalar > Size
Definition: size.h:159
constexpr float kSqrt2
Definition: constants.h:47
constexpr bool IsFinite() const
Definition: round_rect.h:57
static RoundRect MakeRectRadius(const Rect &rect, Scalar radius)
Definition: round_rect.h:27
constexpr const RoundingRadii & GetRadii() const
Definition: round_rect.h:55
static RoundRect MakeRectRadii(const Rect &rect, const RoundingRadii &radii)
Definition: round_rect.cc:9
constexpr bool IsEmpty() const
Definition: round_rect.h:65
static RoundRect MakeOval(const Rect &rect)
Definition: round_rect.h:23
static RoundRect MakeRectXY(const Rect &rect, Scalar x_radius, Scalar y_radius)
Definition: round_rect.h:31
constexpr bool IsRect() const
Definition: round_rect.h:67
RoundRect Expand(Scalar left, Scalar top, Scalar right, Scalar bottom) const
Returns a round rectangle with expanded edges. Negative expansion results in shrinking.
Definition: round_rect.h:98
constexpr const Rect & GetBounds() const
Definition: round_rect.h:53
constexpr bool IsOval() const
Definition: round_rect.h:71
static RoundRect MakeRect(const Rect &rect)
Definition: round_rect.h:19
RoundRect Shift(Scalar dx, Scalar dy) const
Returns a new round rectangle translated by the given offset.
Definition: round_rect.h:89
constexpr TRect< T > Expand(T left, T top, T right, T bottom) const
Returns a rectangle with expanded edges. Negative expansion results in shrinking.
Definition: rect.h:622
constexpr auto GetBottom() const
Definition: rect.h:361
constexpr auto GetTop() const
Definition: rect.h:357
constexpr bool IsEmpty() const
Returns true if either of the width or height are 0, negative, or NaN.
Definition: rect.h:301
constexpr auto GetLeft() const
Definition: rect.h:355
constexpr auto GetRight() const
Definition: rect.h:359
constexpr static TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition: rect.h:136
constexpr static TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition: rect.h:129
Type height
Definition: size.h:29
Type width
Definition: size.h:28