Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(204)

Side by Side Diff: ui/gfx/path_mac_unittest.mm

Issue 1633403002: MacViews: Add native drop shadow to dialogs on OSX < 10.10. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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 #import "ui/gfx/path_mac.h"
6
7 #include <cmath>
8 #include <vector>
9
10 #import <Cocoa/Cocoa.h>
11
12 #include "testing/gtest/include/gtest/gtest.h"
13 #include "third_party/skia/include/core/SkRegion.h"
14 #include "ui/gfx/geometry/rect.h"
15 #include "ui/gfx/geometry/rect_conversions.h"
16 #include "ui/gfx/path.h"
17
18 namespace {
19
20 const double PI = 3.14159265358979323846;
tapted 2016/01/28 05:59:21 SK_ScalarPI?
karandeepb 2016/02/04 03:39:27 Done.
21
22 // Returns the point at a distance of |radius| from the point (|centre_x|,
23 // |centre_y|), and angle |degrees| from the positive horizontal axis, measured
24 // anti-clockwise.
25 NSPoint GetRadialPoint(const double radius,
26 const double degrees,
27 const double centre_x,
28 const double centre_y) {
29 const double radian = (degrees * PI) / 180;
30 return NSMakePoint(centre_x + radius * std::cos(radian),
31 centre_y + radius * std::sin(radian));
32 }
33
34 // Returns the area of a circle with the given |radius|.
35 double CalculateCircleArea(const double radius) {
36 return PI * radius * radius;
37 }
38
39 // Returns the area of a simple polygon. |path| should represent a simple
40 // polygon.
41 double CalculatePolygonArea(NSBezierPath* const path) {
42 // If path represents a single polygon, it will have MoveTo, followed by
43 // multiple LineTo, followed By ClosePath, followed by another MoveTo
44 // NSBezierPathElement.
45 const size_t element_count = [path elementCount];
46 size_t index = 0;
47 NSPoint points[3];
48 std::vector<NSPoint> poly;
49 while (index < element_count) {
50 NSBezierPathElement element =
51 [path elementAtIndex:index++ associatedPoints:points];
52 poly.push_back(points[0]);
53 if (element == NSClosePathBezierPathElement) {
54 DCHECK_EQ(index, element_count - 1);
55 element = [path elementAtIndex:index++ associatedPoints:points];
56 DCHECK_EQ(element, NSMoveToBezierPathElement);
57 break;
58 }
59 DCHECK_EQ(element, index > 1 ? NSLineToBezierPathElement
60 : NSMoveToBezierPathElement);
61 }
62
63 // Shoelace Algorithm to find the area of a simple polygon.
64 const size_t count = poly.size();
65 DCHECK(NSEqualPoints(poly[0], poly[count - 1]));
66 double area = 0;
67 for (size_t i = 0; i < count - 1; i++)
68 area += poly[i].x * poly[i + 1].y - poly[i].y * poly[i + 1].x;
69
70 return std::fabs(area) / 2.0;
71 }
72
73 // Returns the area of a rounded rectangle with the given |width|, |height| and
74 // |radius|.
75 double CalculateRoundedRectangleArea(const double width,
76 const double height,
77 const double radius) {
78 const double inside_width = width - 2 * radius;
79 const double inside_height = height - 2 * radius;
80 return inside_width * inside_height +
81 2 * radius * (inside_width + inside_height) +
82 CalculateCircleArea(radius);
83 }
84
85 // Returns the bounding box of |path| as a gfx::Rect.
86 gfx::Rect GetBoundingBox(NSBezierPath* const path) {
87 const NSRect bounds = [path bounds];
88 return gfx::ToNearestRect(gfx::RectF(bounds.origin.x, bounds.origin.y,
89 bounds.size.width, bounds.size.height));
90 }
91
92 } // namespace
93
94 namespace gfx {
95
96 // Check that empty NSBezierPath is returned for empty SkRegion.
97 TEST(CreateNSBezierPathFromSkRegionTest, EmptyRegion) {
98 NSBezierPath* const result = CreateNSBezierPathFromSkRegion(SkRegion());
99 EXPECT_TRUE([result isEmpty]);
100 }
101
102 // Check that a region containing multiple rectangles is correctly converted to
103 // a NSBezierPath.
104 TEST(CreateNSBezierPathFromSkRegionTest, TwoRectanglesRegion) {
105 const SkIRect rects[] = {
106 {0, 0, 50, 50}, {100, 100, 150, 150},
107 };
108 const NSPoint inside_points[] = {
109 {1, 1}, {1, 49}, {49, 49}, {49, 1}, {101, 101},
110 {101, 149}, {149, 149}, {149, 101}, {25, 25}, {125, 125}};
111 const NSPoint outside_points[] = {{-1, -1}, {-1, 51}, {51, 51}, {51, -1},
112 {99, 99}, {99, 151}, {151, 151}, {151, 99},
113 {75, 75}, {-5, -5}};
114 const size_t kNumPoints = 10;
115 const gfx::Rect expected_bounds(0, 0, 150, 150); // Bounding box of rects.
116 const size_t kSizeRectArray = 2;
117
118 SkRegion region;
119 region.setRects(rects, kSizeRectArray);
120 NSBezierPath* result = CreateNSBezierPathFromSkRegion(region);
121
122 // Check points near the boundary of the path and verify that they are
123 // reported correctly as being inside/outside the path.
124 for (size_t i = 0; i < kNumPoints; i++) {
125 EXPECT_TRUE([result containsPoint:inside_points[i]]);
126 EXPECT_FALSE([result containsPoint:outside_points[i]]);
127 }
128
129 // Verify that the bounding box of |result| is correct.
130 EXPECT_EQ(expected_bounds, GetBoundingBox(result));
131 }
132
133 // Check that empty NSBezierPath is returned for empty SkPath.
134 TEST(CreateNSBezierPathFromSkPathTest, EmptyPath) {
135 NSBezierPath* const result = CreateNSBezierPathFromSkPath(SkPath());
136 EXPECT_TRUE([result isEmpty]);
137 }
138
139 // Check that the returned NSBezierPath has the correct winding rule.
140 TEST(CreateNSBezierPathFromSkPathTest, FillType) {
141 SkPath path;
142 path.setFillType(SkPath::kWinding_FillType);
143 NSBezierPath* result = CreateNSBezierPathFromSkPath(path);
144 EXPECT_EQ(NSNonZeroWindingRule, [result windingRule]);
145
146 path.setFillType(SkPath::kEvenOdd_FillType);
147 result = CreateNSBezierPathFromSkPath(path);
148 EXPECT_EQ(NSEvenOddWindingRule, [result windingRule]);
149
150 // For inverse fill types, the returned NSBezierPath should have the default
151 // winding rule set.
152 path.setFillType(SkPath::kInverseWinding_FillType);
153 result = CreateNSBezierPathFromSkPath(path);
154 EXPECT_EQ([NSBezierPath defaultWindingRule], [result windingRule]);
155
156 path.setFillType(SkPath::kInverseEvenOdd_FillType);
157 result = CreateNSBezierPathFromSkPath(path);
158 EXPECT_EQ([NSBezierPath defaultWindingRule], [result windingRule]);
159 }
160
161 // Check that a path containing multiple subpaths, in this case two rectangles,
162 // is correctly converted to a NSBezierPath.
163 TEST(CreateNSBezierPathFromSkPathTest, TwoRectanglesPath) {
164 const SkRect rects[] = {
165 {0, 0, 50, 50}, {100, 100, 150, 150},
166 };
167 const NSPoint inside_points[] = {
168 {1, 1}, {1, 49}, {49, 49}, {49, 1}, {101, 101},
169 {101, 149}, {149, 149}, {149, 101}, {25, 25}, {125, 125}};
170 const NSPoint outside_points[] = {{-1, -1}, {-1, 51}, {51, 51}, {51, -1},
171 {99, 99}, {99, 151}, {151, 151}, {151, 99},
172 {75, 75}, {-5, -5}};
173 const size_t kNumPoints = 10;
174 const gfx::Rect expected_bounds(0, 0, 150, 150);
175
176 SkPath path;
177 path.addRect(rects[0]);
178 path.addRect(rects[1]);
179 NSBezierPath* result = CreateNSBezierPathFromSkPath(path);
180
181 // Check points near the boundary of the path and verify that they are
182 // reported correctly as being inside/outside the path.
183 for (size_t i = 0; i < kNumPoints; i++) {
184 EXPECT_TRUE([result containsPoint:inside_points[i]]);
185 EXPECT_FALSE([result containsPoint:outside_points[i]]);
186 }
187
188 // Verify that the bounding box of |result| is correct.
189 EXPECT_EQ(expected_bounds, GetBoundingBox(result));
190 }
191
192 // Test that an SKPath containing a circle is converted correctly to a
193 // NSBezierPath.
194 TEST(CreateNSBezierPathFromSkPathTest, CirclePath) {
195 const int kRadius = 5;
196 const int kCentreX = 10;
197 const int kCentreY = 15;
198 const double kCushion = 0.1;
199 // Expected bounding box of the circle.
200 const gfx::Rect expected_bounds(kCentreX - kRadius, kCentreY - kRadius,
201 2 * kRadius, 2 * kRadius);
202
203 SkPath path;
204 path.addCircle(SkIntToScalar(kCentreX), SkIntToScalar(kCentreY),
205 SkIntToScalar(kRadius));
206 NSBezierPath* const result = CreateNSBezierPathFromSkPath(path);
207
208 // Check points near the boundary of the circle and verify that they are
209 // reported correctly as being inside/outside the path.
210 for (size_t deg = 0; deg < 360; deg++) {
211 NSPoint inside_point =
212 GetRadialPoint(kRadius - kCushion, deg, kCentreX, kCentreY);
213 NSPoint outside_point =
214 GetRadialPoint(kRadius + kCushion, deg, kCentreX, kCentreY);
215 EXPECT_TRUE([result containsPoint:inside_point]);
216 EXPECT_FALSE([result containsPoint:outside_point]);
217 }
218
219 // Check that the returned result has the correct bounding box.
220 EXPECT_EQ(expected_bounds, GetBoundingBox(result));
221
222 // Check area of converted path is correct upto a certain tolerance value. To
223 // find the area of the NSBezierPath returned, flatten it i.e. convert it to a
224 // polygon.
225 [NSBezierPath setDefaultFlatness:0.01];
226 NSBezierPath* const polygon = [result bezierPathByFlatteningPath];
227 const double kTolerance = 0.5;
228 EXPECT_NEAR(CalculateCircleArea(kRadius), CalculatePolygonArea(polygon),
229 kTolerance);
230 }
231
232 // Test that an SKPath containing a rounded rectangle is converted correctly to
233 // a NSBezierPath.
234 TEST(CreateNSBezierPathFromSkPathTest, RoundedRectanglePath) {
235 const int kRectangleWidth = 50;
236 const int kRectangleHeight = 100;
237 const int kCornerRadius = 5;
238 const double kCushion = 0.1;
239 // Expected bounding box of the rounded rectangle.
240 const gfx::Rect expected_bounds(kRectangleWidth, kRectangleHeight);
241
242 SkRRect rrect;
243 rrect.setRectXY(SkRect::MakeWH(kRectangleWidth, kRectangleHeight),
244 kCornerRadius, kCornerRadius);
245
246 const NSPoint inside_points[] = {
247 // Bottom left corner.
248 {kCornerRadius, kCornerRadius},
249 // Bottom right corner.
250 {kRectangleWidth - kCornerRadius, kCornerRadius},
251 // Top Right corner.
252 {kRectangleWidth - kCornerRadius, kRectangleHeight - kCornerRadius},
253 // Top left corner.
254 {kCornerRadius, kRectangleHeight - kCornerRadius},
255 // Bottom middle.
256 {kRectangleWidth / 2.0, kCushion},
257 // Right middle.
258 {kRectangleWidth - kCushion, kRectangleHeight / 2.0},
259 // Top middle.
260 {kRectangleWidth / 2.0, kRectangleHeight - kCushion},
261 // Left middle.
262 {kCushion, kRectangleHeight / 2.0}};
263 const NSPoint outside_points[] = {
264 // Bottom left corner.
265 {0, 0},
266 // Bottom right corner.
267 {kRectangleWidth, 0},
268 // Top right corner.
269 {kRectangleWidth, kRectangleHeight},
270 // Top left corner.
271 {0, kRectangleHeight},
272 // Bottom middle.
273 {kRectangleWidth / 2.0, -kCushion},
274 // Right middle.
275 {kRectangleWidth + kCushion, kRectangleHeight / 2.0},
276 // Top middle.
277 {kRectangleWidth / 2.0, kRectangleHeight + kCushion},
278 // Left middle.
279 {-kCushion, kRectangleHeight / 2.0}};
280 const size_t kNumPoints = 8;
281
282 SkPath path;
283 path.addRRect(rrect);
284 NSBezierPath* const result = CreateNSBezierPathFromSkPath(path);
285
286 // Check points near the boundary of the path and verify that they are
287 // reported correctly as being inside/outside the path.
288 for (size_t i = 0; i < kNumPoints; i++) {
289 EXPECT_TRUE([result containsPoint:inside_points[i]]);
290 EXPECT_FALSE([result containsPoint:outside_points[i]]);
291 }
292
293 // Check that the returned result has the correct bounding box.
294 EXPECT_EQ(expected_bounds, GetBoundingBox(result));
295
296 // Check area of converted path is correct upto a certain tolerance value. To
297 // find the area of the NSBezierPath returned, flatten it i.e. convert it to a
298 // polygon.
299 [NSBezierPath setDefaultFlatness:0.01];
300 NSBezierPath* const polygon = [result bezierPathByFlatteningPath];
301 const double kTolerance = 0.5;
302 EXPECT_NEAR(CalculateRoundedRectangleArea(kRectangleWidth, kRectangleHeight,
303 kCornerRadius),
304 CalculatePolygonArea(polygon), kTolerance);
305 }
306
307 } // namespace gfx
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698