1// Copyright (c) 2012 The Chromium 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 "base/basictypes.h"
6#include "testing/gtest/include/gtest/gtest.h"
7#include "ui/gfx/geometry/quad_f.h"
8#include "ui/gfx/geometry/rect_f.h"
9
10namespace gfx {
11
12TEST(QuadTest, Construction) {
13  // Verify constructors.
14  PointF a(1, 1);
15  PointF b(2, 1);
16  PointF c(2, 2);
17  PointF d(1, 2);
18  PointF e;
19  QuadF q1;
20  QuadF q2(e, e, e, e);
21  QuadF q3(a, b, c, d);
22  QuadF q4(BoundingRect(a, c));
23  EXPECT_EQ(q1, q2);
24  EXPECT_EQ(q3, q4);
25
26  // Verify getters.
27  EXPECT_EQ(q3.p1(), a);
28  EXPECT_EQ(q3.p2(), b);
29  EXPECT_EQ(q3.p3(), c);
30  EXPECT_EQ(q3.p4(), d);
31
32  // Verify setters.
33  q3.set_p1(b);
34  q3.set_p2(c);
35  q3.set_p3(d);
36  q3.set_p4(a);
37  EXPECT_EQ(q3.p1(), b);
38  EXPECT_EQ(q3.p2(), c);
39  EXPECT_EQ(q3.p3(), d);
40  EXPECT_EQ(q3.p4(), a);
41
42  // Verify operator=(Rect)
43  EXPECT_NE(q1, q4);
44  q1 = BoundingRect(a, c);
45  EXPECT_EQ(q1, q4);
46
47  // Verify operator=(Quad)
48  EXPECT_NE(q1, q3);
49  q1 = q3;
50  EXPECT_EQ(q1, q3);
51}
52
53TEST(QuadTest, AddingVectors) {
54  PointF a(1, 1);
55  PointF b(2, 1);
56  PointF c(2, 2);
57  PointF d(1, 2);
58  Vector2dF v(3.5f, -2.5f);
59
60  QuadF q1(a, b, c, d);
61  QuadF added = q1 + v;
62  q1 += v;
63  QuadF expected1(PointF(4.5f, -1.5f),
64                  PointF(5.5f, -1.5f),
65                  PointF(5.5f, -0.5f),
66                  PointF(4.5f, -0.5f));
67  EXPECT_EQ(expected1, added);
68  EXPECT_EQ(expected1, q1);
69
70  QuadF q2(a, b, c, d);
71  QuadF subtracted = q2 - v;
72  q2 -= v;
73  QuadF expected2(PointF(-2.5f, 3.5f),
74                  PointF(-1.5f, 3.5f),
75                  PointF(-1.5f, 4.5f),
76                  PointF(-2.5f, 4.5f));
77  EXPECT_EQ(expected2, subtracted);
78  EXPECT_EQ(expected2, q2);
79
80  QuadF q3(a, b, c, d);
81  q3 += v;
82  q3 -= v;
83  EXPECT_EQ(QuadF(a, b, c, d), q3);
84  EXPECT_EQ(q3, (q3 + v - v));
85}
86
87TEST(QuadTest, IsRectilinear) {
88  PointF a(1, 1);
89  PointF b(2, 1);
90  PointF c(2, 2);
91  PointF d(1, 2);
92  Vector2dF v(3.5f, -2.5f);
93
94  EXPECT_TRUE(QuadF().IsRectilinear());
95  EXPECT_TRUE(QuadF(a, b, c, d).IsRectilinear());
96  EXPECT_TRUE((QuadF(a, b, c, d) + v).IsRectilinear());
97
98  float epsilon = std::numeric_limits<float>::epsilon();
99  PointF a2(1 + epsilon / 2, 1 + epsilon / 2);
100  PointF b2(2 + epsilon / 2, 1 + epsilon / 2);
101  PointF c2(2 + epsilon / 2, 2 + epsilon / 2);
102  PointF d2(1 + epsilon / 2, 2 + epsilon / 2);
103  EXPECT_TRUE(QuadF(a2, b, c, d).IsRectilinear());
104  EXPECT_TRUE((QuadF(a2, b, c, d) + v).IsRectilinear());
105  EXPECT_TRUE(QuadF(a, b2, c, d).IsRectilinear());
106  EXPECT_TRUE((QuadF(a, b2, c, d) + v).IsRectilinear());
107  EXPECT_TRUE(QuadF(a, b, c2, d).IsRectilinear());
108  EXPECT_TRUE((QuadF(a, b, c2, d) + v).IsRectilinear());
109  EXPECT_TRUE(QuadF(a, b, c, d2).IsRectilinear());
110  EXPECT_TRUE((QuadF(a, b, c, d2) + v).IsRectilinear());
111
112  struct {
113    PointF a_off, b_off, c_off, d_off;
114  } tests[] = {
115    {
116      PointF(1, 1.00001f),
117      PointF(2, 1.00001f),
118      PointF(2, 2.00001f),
119      PointF(1, 2.00001f)
120    },
121    {
122      PointF(1.00001f, 1),
123      PointF(2.00001f, 1),
124      PointF(2.00001f, 2),
125      PointF(1.00001f, 2)
126    },
127    {
128      PointF(1.00001f, 1.00001f),
129      PointF(2.00001f, 1.00001f),
130      PointF(2.00001f, 2.00001f),
131      PointF(1.00001f, 2.00001f)
132    },
133    {
134      PointF(1, 0.99999f),
135      PointF(2, 0.99999f),
136      PointF(2, 1.99999f),
137      PointF(1, 1.99999f)
138    },
139    {
140      PointF(0.99999f, 1),
141      PointF(1.99999f, 1),
142      PointF(1.99999f, 2),
143      PointF(0.99999f, 2)
144    },
145    {
146      PointF(0.99999f, 0.99999f),
147      PointF(1.99999f, 0.99999f),
148      PointF(1.99999f, 1.99999f),
149      PointF(0.99999f, 1.99999f)
150    }
151  };
152
153  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
154    PointF a_off = tests[i].a_off;
155    PointF b_off = tests[i].b_off;
156    PointF c_off = tests[i].c_off;
157    PointF d_off = tests[i].d_off;
158
159    EXPECT_FALSE(QuadF(a_off, b, c, d).IsRectilinear());
160    EXPECT_FALSE((QuadF(a_off, b, c, d) + v).IsRectilinear());
161    EXPECT_FALSE(QuadF(a, b_off, c, d).IsRectilinear());
162    EXPECT_FALSE((QuadF(a, b_off, c, d) + v).IsRectilinear());
163    EXPECT_FALSE(QuadF(a, b, c_off, d).IsRectilinear());
164    EXPECT_FALSE((QuadF(a, b, c_off, d) + v).IsRectilinear());
165    EXPECT_FALSE(QuadF(a, b, c, d_off).IsRectilinear());
166    EXPECT_FALSE((QuadF(a, b, c, d_off) + v).IsRectilinear());
167    EXPECT_FALSE(QuadF(a_off, b, c_off, d).IsRectilinear());
168    EXPECT_FALSE((QuadF(a_off, b, c_off, d) + v).IsRectilinear());
169    EXPECT_FALSE(QuadF(a, b_off, c, d_off).IsRectilinear());
170    EXPECT_FALSE((QuadF(a, b_off, c, d_off) + v).IsRectilinear());
171    EXPECT_FALSE(QuadF(a, b_off, c_off, d_off).IsRectilinear());
172    EXPECT_FALSE((QuadF(a, b_off, c_off, d_off) + v).IsRectilinear());
173    EXPECT_FALSE(QuadF(a_off, b, c_off, d_off).IsRectilinear());
174    EXPECT_FALSE((QuadF(a_off, b, c_off, d_off) + v).IsRectilinear());
175    EXPECT_FALSE(QuadF(a_off, b_off, c, d_off).IsRectilinear());
176    EXPECT_FALSE((QuadF(a_off, b_off, c, d_off) + v).IsRectilinear());
177    EXPECT_FALSE(QuadF(a_off, b_off, c_off, d).IsRectilinear());
178    EXPECT_FALSE((QuadF(a_off, b_off, c_off, d) + v).IsRectilinear());
179    EXPECT_TRUE(QuadF(a_off, b_off, c_off, d_off).IsRectilinear());
180    EXPECT_TRUE((QuadF(a_off, b_off, c_off, d_off) + v).IsRectilinear());
181  }
182}
183
184TEST(QuadTest, IsCounterClockwise) {
185  PointF a1(1, 1);
186  PointF b1(2, 1);
187  PointF c1(2, 2);
188  PointF d1(1, 2);
189  EXPECT_FALSE(QuadF(a1, b1, c1, d1).IsCounterClockwise());
190  EXPECT_FALSE(QuadF(b1, c1, d1, a1).IsCounterClockwise());
191  EXPECT_TRUE(QuadF(a1, d1, c1, b1).IsCounterClockwise());
192  EXPECT_TRUE(QuadF(c1, b1, a1, d1).IsCounterClockwise());
193
194  // Slightly more complicated quads should work just as easily.
195  PointF a2(1.3f, 1.4f);
196  PointF b2(-0.7f, 4.9f);
197  PointF c2(1.8f, 6.2f);
198  PointF d2(2.1f, 1.6f);
199  EXPECT_TRUE(QuadF(a2, b2, c2, d2).IsCounterClockwise());
200  EXPECT_TRUE(QuadF(b2, c2, d2, a2).IsCounterClockwise());
201  EXPECT_FALSE(QuadF(a2, d2, c2, b2).IsCounterClockwise());
202  EXPECT_FALSE(QuadF(c2, b2, a2, d2).IsCounterClockwise());
203
204  // Quads with 3 collinear points should work correctly, too.
205  PointF a3(0, 0);
206  PointF b3(1, 0);
207  PointF c3(2, 0);
208  PointF d3(1, 1);
209  EXPECT_FALSE(QuadF(a3, b3, c3, d3).IsCounterClockwise());
210  EXPECT_FALSE(QuadF(b3, c3, d3, a3).IsCounterClockwise());
211  EXPECT_TRUE(QuadF(a3, d3, c3, b3).IsCounterClockwise());
212  // The next expectation in particular would fail for an implementation
213  // that incorrectly uses only a cross product of the first 3 vertices.
214  EXPECT_TRUE(QuadF(c3, b3, a3, d3).IsCounterClockwise());
215
216  // Non-convex quads should work correctly, too.
217  PointF a4(0, 0);
218  PointF b4(1, 1);
219  PointF c4(2, 0);
220  PointF d4(1, 3);
221  EXPECT_FALSE(QuadF(a4, b4, c4, d4).IsCounterClockwise());
222  EXPECT_FALSE(QuadF(b4, c4, d4, a4).IsCounterClockwise());
223  EXPECT_TRUE(QuadF(a4, d4, c4, b4).IsCounterClockwise());
224  EXPECT_TRUE(QuadF(c4, b4, a4, d4).IsCounterClockwise());
225
226  // A quad with huge coordinates should not fail this check due to
227  // single-precision overflow.
228  PointF a5(1e30f, 1e30f);
229  PointF b5(1e35f, 1e30f);
230  PointF c5(1e35f, 1e35f);
231  PointF d5(1e30f, 1e35f);
232  EXPECT_FALSE(QuadF(a5, b5, c5, d5).IsCounterClockwise());
233  EXPECT_FALSE(QuadF(b5, c5, d5, a5).IsCounterClockwise());
234  EXPECT_TRUE(QuadF(a5, d5, c5, b5).IsCounterClockwise());
235  EXPECT_TRUE(QuadF(c5, b5, a5, d5).IsCounterClockwise());
236}
237
238TEST(QuadTest, BoundingBox) {
239  RectF r(3.2f, 5.4f, 7.007f, 12.01f);
240  EXPECT_EQ(r, QuadF(r).BoundingBox());
241
242  PointF a(1.3f, 1.4f);
243  PointF b(-0.7f, 4.9f);
244  PointF c(1.8f, 6.2f);
245  PointF d(2.1f, 1.6f);
246  float left = -0.7f;
247  float top = 1.4f;
248  float right = 2.1f;
249  float bottom = 6.2f;
250  EXPECT_EQ(RectF(left, top, right - left, bottom - top),
251            QuadF(a, b, c, d).BoundingBox());
252}
253
254TEST(QuadTest, ContainsPoint) {
255  PointF a(1.3f, 1.4f);
256  PointF b(-0.8f, 4.4f);
257  PointF c(1.8f, 6.1f);
258  PointF d(2.1f, 1.6f);
259
260  Vector2dF epsilon_x(2 * std::numeric_limits<float>::epsilon(), 0);
261  Vector2dF epsilon_y(0, 2 * std::numeric_limits<float>::epsilon());
262
263  Vector2dF ac_center = c - a;
264  ac_center.Scale(0.5f);
265  Vector2dF bd_center = d - b;
266  bd_center.Scale(0.5f);
267
268  EXPECT_TRUE(QuadF(a, b, c, d).Contains(a + ac_center));
269  EXPECT_TRUE(QuadF(a, b, c, d).Contains(b + bd_center));
270  EXPECT_TRUE(QuadF(a, b, c, d).Contains(c - ac_center));
271  EXPECT_TRUE(QuadF(a, b, c, d).Contains(d - bd_center));
272  EXPECT_FALSE(QuadF(a, b, c, d).Contains(a - ac_center));
273  EXPECT_FALSE(QuadF(a, b, c, d).Contains(b - bd_center));
274  EXPECT_FALSE(QuadF(a, b, c, d).Contains(c + ac_center));
275  EXPECT_FALSE(QuadF(a, b, c, d).Contains(d + bd_center));
276
277  EXPECT_TRUE(QuadF(a, b, c, d).Contains(a));
278  EXPECT_FALSE(QuadF(a, b, c, d).Contains(a - epsilon_x));
279  EXPECT_FALSE(QuadF(a, b, c, d).Contains(a - epsilon_y));
280  EXPECT_FALSE(QuadF(a, b, c, d).Contains(a + epsilon_x));
281  EXPECT_TRUE(QuadF(a, b, c, d).Contains(a + epsilon_y));
282
283  EXPECT_TRUE(QuadF(a, b, c, d).Contains(b));
284  EXPECT_FALSE(QuadF(a, b, c, d).Contains(b - epsilon_x));
285  EXPECT_FALSE(QuadF(a, b, c, d).Contains(b - epsilon_y));
286  EXPECT_TRUE(QuadF(a, b, c, d).Contains(b + epsilon_x));
287  EXPECT_FALSE(QuadF(a, b, c, d).Contains(b + epsilon_y));
288
289  EXPECT_TRUE(QuadF(a, b, c, d).Contains(c));
290  EXPECT_FALSE(QuadF(a, b, c, d).Contains(c - epsilon_x));
291  EXPECT_TRUE(QuadF(a, b, c, d).Contains(c - epsilon_y));
292  EXPECT_FALSE(QuadF(a, b, c, d).Contains(c + epsilon_x));
293  EXPECT_FALSE(QuadF(a, b, c, d).Contains(c + epsilon_y));
294
295  EXPECT_TRUE(QuadF(a, b, c, d).Contains(d));
296  EXPECT_TRUE(QuadF(a, b, c, d).Contains(d - epsilon_x));
297  EXPECT_FALSE(QuadF(a, b, c, d).Contains(d - epsilon_y));
298  EXPECT_FALSE(QuadF(a, b, c, d).Contains(d + epsilon_x));
299  EXPECT_FALSE(QuadF(a, b, c, d).Contains(d + epsilon_y));
300
301  // Test a simple square.
302  PointF s1(-1, -1);
303  PointF s2(1, -1);
304  PointF s3(1, 1);
305  PointF s4(-1, 1);
306  // Top edge.
307  EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.1f, -1.0f)));
308  EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, -1.0f)));
309  EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(0.0f, -1.0f)));
310  EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, -1.0f)));
311  EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(1.1f, -1.0f)));
312  // Bottom edge.
313  EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.1f, 1.0f)));
314  EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, 1.0f)));
315  EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(0.0f, 1.0f)));
316  EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, 1.0f)));
317  EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(1.1f, 1.0f)));
318  // Left edge.
319  EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, -1.1f)));
320  EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, -1.0f)));
321  EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, 0.0f)));
322  EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, 1.0f)));
323  EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, 1.1f)));
324  // Right edge.
325  EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, -1.1f)));
326  EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, -1.0f)));
327  EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, 0.0f)));
328  EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, 1.0f)));
329  EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, 1.1f)));
330  // Centered inside.
331  EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(0, 0)));
332  // Centered outside.
333  EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.1f, 0)));
334  EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(1.1f, 0)));
335  EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(0, -1.1f)));
336  EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(0, 1.1f)));
337}
338
339TEST(QuadTest, Scale) {
340  PointF a(1.3f, 1.4f);
341  PointF b(-0.8f, 4.4f);
342  PointF c(1.8f, 6.1f);
343  PointF d(2.1f, 1.6f);
344  QuadF q1(a, b, c, d);
345  q1.Scale(1.5f);
346
347  PointF a_scaled = ScalePoint(a, 1.5f);
348  PointF b_scaled = ScalePoint(b, 1.5f);
349  PointF c_scaled = ScalePoint(c, 1.5f);
350  PointF d_scaled = ScalePoint(d, 1.5f);
351  EXPECT_EQ(q1, QuadF(a_scaled, b_scaled, c_scaled, d_scaled));
352
353  QuadF q2;
354  q2.Scale(1.5f);
355  EXPECT_EQ(q2, q2);
356}
357
358}  // namespace gfx
359