1/*
2 * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above
9 *    copyright notice, this list of conditions and the following
10 *    disclaimer.
11 * 2. Redistributions in binary form must reproduce the above
12 *    copyright notice, this list of conditions and the following
13 *    disclaimer in the documentation and/or other materials
14 *    provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
20 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
21 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
27 * OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include "config.h"
31
32#include "platform/geometry/FloatRoundedRect.h"
33
34#include <gtest/gtest.h>
35
36using namespace blink;
37
38namespace blink {
39
40void PrintTo(const FloatSize& size, std::ostream* os)
41{
42    *os << "FloatSize("
43        << size.width() << ", "
44        << size.height() << ")";
45}
46
47void PrintTo(const FloatRect& rect, std::ostream* os)
48{
49    *os << "FloatRect("
50        << rect.x() << ", "
51        << rect.y() << ", "
52        << rect.width() << ", "
53        << rect.height() << ")";
54}
55
56void PrintTo(const FloatRoundedRect::Radii& radii, std::ostream* os)
57{
58    *os << "FloatRoundedRect::Radii("
59        << ::testing::PrintToString(radii.topLeft()) << ", "
60        << ::testing::PrintToString(radii.topRight()) << ", "
61        << ::testing::PrintToString(radii.bottomRight()) << ", "
62        << ::testing::PrintToString(radii.bottomLeft()) << ")";
63}
64
65void PrintTo(const FloatRoundedRect& roundedRect, std::ostream* os)
66{
67    *os << "FloatRoundedRect("
68        << ::testing::PrintToString(roundedRect.rect()) << ", "
69        << ::testing::PrintToString(roundedRect.radii()) << ")";
70}
71
72} // namespace blink
73
74namespace {
75
76#define TEST_INTERCEPTS(roundedRect, yCoordinate, expectedMinXIntercept, expectedMaxXIntercept) \
77{                                                                                               \
78    float minXIntercept;                                                                        \
79    float maxXIntercept;                                                                        \
80    EXPECT_TRUE(roundedRect.xInterceptsAtY(yCoordinate, minXIntercept, maxXIntercept));         \
81    EXPECT_FLOAT_EQ(expectedMinXIntercept, minXIntercept);                                      \
82    EXPECT_FLOAT_EQ(expectedMaxXIntercept, maxXIntercept);                                      \
83}
84
85TEST(FloatRoundedRectTest, zeroRadii)
86{
87    FloatRoundedRect r = FloatRoundedRect(1, 2, 3, 4);
88
89    EXPECT_EQ(FloatRect(1, 2, 3, 4), r.rect());
90    EXPECT_EQ(FloatSize(), r.radii().topLeft());
91    EXPECT_EQ(FloatSize(), r.radii().topRight());
92    EXPECT_EQ(FloatSize(), r.radii().bottomLeft());
93    EXPECT_EQ(FloatSize(), r.radii().bottomRight());
94    EXPECT_TRUE(r.radii().isZero());
95    EXPECT_FALSE(r.isRounded());
96    EXPECT_FALSE(r.isEmpty());
97
98    EXPECT_EQ(FloatRect(1, 2, 0, 0), r.topLeftCorner());
99    EXPECT_EQ(FloatRect(4, 2, 0, 0), r.topRightCorner());
100    EXPECT_EQ(FloatRect(4, 6, 0, 0), r.bottomRightCorner());
101    EXPECT_EQ(FloatRect(1, 6, 0, 0), r.bottomLeftCorner());
102
103    TEST_INTERCEPTS(r, 2, r.rect().x(), r.rect().maxX());
104    TEST_INTERCEPTS(r, 4, r.rect().x(), r.rect().maxX());
105    TEST_INTERCEPTS(r, 6, r.rect().x(), r.rect().maxX());
106
107    float minXIntercept;
108    float maxXIntercept;
109
110    EXPECT_FALSE(r.xInterceptsAtY(1, minXIntercept, maxXIntercept));
111    EXPECT_FALSE(r.xInterceptsAtY(7, minXIntercept, maxXIntercept));
112
113    // The FloatRoundedRect::expandRadii() function doesn't change radii FloatSizes that
114    // are <= zero. Same as RoundedRect::expandRadii().
115    r.expandRadii(20);
116    r.shrinkRadii(10);
117    EXPECT_TRUE(r.radii().isZero());
118}
119
120TEST(FloatRoundedRectTest, circle)
121{
122    FloatSize cornerRadii(50, 50);
123    FloatRoundedRect r(FloatRect(0, 0, 100, 100), cornerRadii, cornerRadii, cornerRadii, cornerRadii);
124
125    EXPECT_EQ(FloatRect(0, 0, 100, 100), r.rect());
126    EXPECT_EQ(cornerRadii, r.radii().topLeft());
127    EXPECT_EQ(cornerRadii, r.radii().topRight());
128    EXPECT_EQ(cornerRadii, r.radii().bottomLeft());
129    EXPECT_EQ(cornerRadii, r.radii().bottomRight());
130    EXPECT_FALSE(r.radii().isZero());
131    EXPECT_TRUE(r.isRounded());
132    EXPECT_FALSE(r.isEmpty());
133
134    EXPECT_EQ(FloatRect(0, 0, 50, 50), r.topLeftCorner());
135    EXPECT_EQ(FloatRect(50, 0, 50, 50), r.topRightCorner());
136    EXPECT_EQ(FloatRect(0, 50, 50, 50), r.bottomLeftCorner());
137    EXPECT_EQ(FloatRect(50, 50, 50, 50), r.bottomRightCorner());
138
139    TEST_INTERCEPTS(r, 0, 50, 50);
140    TEST_INTERCEPTS(r, 25, 6.69873, 93.3013);
141    TEST_INTERCEPTS(r, 50, 0, 100);
142    TEST_INTERCEPTS(r, 75, 6.69873, 93.3013);
143    TEST_INTERCEPTS(r, 100, 50, 50);
144
145    float minXIntercept;
146    float maxXIntercept;
147
148    EXPECT_FALSE(r.xInterceptsAtY(-1, minXIntercept, maxXIntercept));
149    EXPECT_FALSE(r.xInterceptsAtY(101, minXIntercept, maxXIntercept));
150}
151
152/*
153 * FloatRoundedRect geometry for this test. Corner radii are in parens, x and y intercepts
154 * for the elliptical corners are noted. The rectangle itself is at 0,0 with width and height 100.
155 *
156 *         (10, 15)  x=10      x=90 (10, 20)
157 *                (--+---------+--)
158 *           y=15 +--|         |-+ y=20
159 *                |               |
160 *                |               |
161 *           y=85 + -|         |- + y=70
162 *                (--+---------+--)
163 *       (25, 15)  x=25      x=80  (20, 30)
164 */
165TEST(FloatRoundedRectTest, ellipticalCorners)
166{
167    FloatSize cornerSize(10, 20);
168    FloatRoundedRect::Radii cornerRadii;
169    cornerRadii.setTopLeft(FloatSize(10, 15));
170    cornerRadii.setTopRight(FloatSize(10, 20));
171    cornerRadii.setBottomLeft(FloatSize(25, 15));
172    cornerRadii.setBottomRight(FloatSize(20, 30));
173
174    FloatRoundedRect r(FloatRect(0, 0, 100, 100), cornerRadii);
175
176    EXPECT_EQ(r.radii(), FloatRoundedRect::Radii(FloatSize(10, 15), FloatSize(10, 20), FloatSize(25, 15), FloatSize(20, 30)));
177    EXPECT_EQ(r, FloatRoundedRect(FloatRect(0, 0, 100, 100), cornerRadii));
178
179    EXPECT_EQ(FloatRect(0, 0, 10, 15), r.topLeftCorner());
180    EXPECT_EQ(FloatRect(90, 0, 10, 20), r.topRightCorner());
181    EXPECT_EQ(FloatRect(0, 85, 25, 15), r.bottomLeftCorner());
182    EXPECT_EQ(FloatRect(80, 70, 20, 30), r.bottomRightCorner());
183
184    TEST_INTERCEPTS(r, 5, 2.5464401, 96.61438);
185    TEST_INTERCEPTS(r, 15, 0, 99.682457);
186    TEST_INTERCEPTS(r, 20, 0, 100);
187    TEST_INTERCEPTS(r, 50, 0, 100);
188    TEST_INTERCEPTS(r, 70, 0, 100);
189    TEST_INTERCEPTS(r, 85, 0, 97.320511);
190    TEST_INTERCEPTS(r, 95, 6.3661003, 91.05542);
191
192    float minXIntercept;
193    float maxXIntercept;
194
195    EXPECT_FALSE(r.xInterceptsAtY(-1, minXIntercept, maxXIntercept));
196    EXPECT_FALSE(r.xInterceptsAtY(101, minXIntercept, maxXIntercept));
197}
198
199} // namespace
200
201