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

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: Removed tests in CreateNSBezierPathFromSkPathTest.FillType in path_mac_unittest.mm 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 // Returns the point at a distance of |radius| from the point (|centre_x|,
21 // |centre_y|), and angle |degrees| from the positive horizontal axis, measured
22 // anti-clockwise.
23 NSPoint GetRadialPoint(const double radius,
tapted 2016/02/05 04:51:07 nit: it's unusual to put `const` on arguments of p
karandeepb 2016/02/08 07:47:09 Done.
24 const double degrees,
25 const double centre_x,
26 const double centre_y) {
27 const double radian = (degrees * SK_ScalarPI) / 180;
28 return NSMakePoint(centre_x + radius * std::cos(radian),
29 centre_y + radius * std::sin(radian));
30 }
31
32 // Returns the area of a circle with the given |radius|.
33 double CalculateCircleArea(const double radius) {
34 return SK_ScalarPI * radius * radius;
35 }
36
37 // Returns the area of a simple polygon. |path| should represent a simple
38 // polygon.
39 double CalculatePolygonArea(NSBezierPath* const path) {
karandeepb 2016/02/08 07:47:09 This function somewhat depends on the internal NSB
40 // If path represents a single polygon, it will have MoveTo, followed by
41 // multiple LineTo, followed By ClosePath, followed by another MoveTo
42 // NSBezierPathElement.
43 const size_t element_count = [path elementCount];
44 size_t index = 0;
45 NSPoint points[3];
46 std::vector<NSPoint> poly;
47 while (index < element_count) {
48 NSBezierPathElement element =
49 [path elementAtIndex:index++ associatedPoints:points];
tapted 2016/02/05 04:51:07 The `index++` is easy to lose here - can this be a
karandeepb 2016/02/08 07:47:09 Done.
50 poly.push_back(points[0]);
51 if (element == NSClosePathBezierPathElement) {
52 DCHECK_EQ(index, element_count - 1);
53 element = [path elementAtIndex:index++ associatedPoints:points];
tapted 2016/02/05 04:51:07 `index++` doesn't look right on this line
karandeepb 2016/02/08 07:47:09 Done.
54 DCHECK_EQ(element, NSMoveToBezierPathElement);
55 break;
56 }
57 DCHECK_EQ(element, index > 1 ? NSLineToBezierPathElement
58 : NSMoveToBezierPathElement);
59 }
60
61 // Shoelace Algorithm to find the area of a simple polygon.
62 const size_t count = poly.size();
63 DCHECK(NSEqualPoints(poly[0], poly[count - 1]));
tapted 2016/02/05 04:51:07 poly.front(), poly.back()?
karandeepb 2016/02/08 07:47:09 Done.
64 double area = 0;
65 for (size_t i = 0; i < count - 1; i++)
tapted 2016/02/05 04:51:07 then poly.size() can be moved in here
karandeepb 2016/02/08 07:47:09 Done.
66 area += poly[i].x * poly[i + 1].y - poly[i].y * poly[i + 1].x;
67
68 return std::fabs(area) / 2.0;
69 }
70
71 // Returns the area of a rounded rectangle with the given |width|, |height| and
72 // |radius|.
73 double CalculateRoundedRectangleArea(const double width,
74 const double height,
75 const double radius) {
76 const double inside_width = width - 2 * radius;
77 const double inside_height = height - 2 * radius;
78 return inside_width * inside_height +
79 2 * radius * (inside_width + inside_height) +
80 CalculateCircleArea(radius);
81 }
82
83 // Returns the bounding box of |path| as a gfx::Rect.
84 gfx::Rect GetBoundingBox(NSBezierPath* const path) {
85 const NSRect bounds = [path bounds];
86 return gfx::ToNearestRect(gfx::RectF(bounds.origin.x, bounds.origin.y,
87 bounds.size.width, bounds.size.height));
88 }
89
90 } // namespace
91
92 namespace gfx {
93
94 // Check that empty NSBezierPath is returned for empty SkRegion.
95 TEST(CreateNSBezierPathFromSkRegionTest, EmptyRegion) {
96 NSBezierPath* const result = CreateNSBezierPathFromSkRegion(SkRegion());
tapted 2016/02/05 04:51:07 nit: no const (const typically looks extra weird a
karandeepb 2016/02/08 07:47:09 Done.
97 EXPECT_TRUE([result isEmpty]);
98 }
99
100 // Check that a region containing multiple rectangles is correctly converted to
101 // a NSBezierPath.
102 TEST(CreateNSBezierPathFromSkRegionTest, TwoRectanglesRegion) {
103 const SkIRect rects[] = {
104 {0, 0, 50, 50}, {100, 100, 150, 150},
105 };
106 const NSPoint inside_points[] = {
tapted 2016/02/05 04:51:07 these consts look fine though, since NSPoint is a
karandeepb 2016/02/08 07:47:09 Done.
107 {1, 1}, {1, 49}, {49, 49}, {49, 1}, {101, 101},
108 {101, 149}, {149, 149}, {149, 101}, {25, 25}, {125, 125}};
109 const NSPoint outside_points[] = {{-1, -1}, {-1, 51}, {51, 51}, {51, -1},
110 {99, 99}, {99, 151}, {151, 151}, {151, 99},
111 {75, 75}, {-5, -5}};
112 const size_t kNumPoints = 10;
113 const gfx::Rect expected_bounds(0, 0, 150, 150); // Bounding box of rects.
114 const size_t kSizeRectArray = 2;
tapted 2016/02/05 04:51:07 = arraysize(rects)? or just use arraysize(rects) i
karandeepb 2016/02/08 07:47:09 Done.
115
116 SkRegion region;
117 region.setRects(rects, kSizeRectArray);
118 NSBezierPath* result = CreateNSBezierPathFromSkRegion(region);
119
120 // Check points near the boundary of the path and verify that they are
121 // reported correctly as being inside/outside the path.
122 for (size_t i = 0; i < kNumPoints; i++) {
123 EXPECT_TRUE([result containsPoint:inside_points[i]]);
124 EXPECT_FALSE([result containsPoint:outside_points[i]]);
125 }
126
127 // Verify that the bounding box of |result| is correct.
128 EXPECT_EQ(expected_bounds, GetBoundingBox(result));
129 }
130
131 // Check that empty NSBezierPath is returned for empty SkPath.
132 TEST(CreateNSBezierPathFromSkPathTest, EmptyPath) {
133 NSBezierPath* const result = CreateNSBezierPathFromSkPath(SkPath());
134 EXPECT_TRUE([result isEmpty]);
135 }
136
137 // Check that the returned NSBezierPath has the correct winding rule.
138 TEST(CreateNSBezierPathFromSkPathTest, FillType) {
139 SkPath path;
140 path.setFillType(SkPath::kWinding_FillType);
141 NSBezierPath* result = CreateNSBezierPathFromSkPath(path);
142 EXPECT_EQ(NSNonZeroWindingRule, [result windingRule]);
143
144 path.setFillType(SkPath::kEvenOdd_FillType);
145 result = CreateNSBezierPathFromSkPath(path);
146 EXPECT_EQ(NSEvenOddWindingRule, [result windingRule]);
147 }
148
149 // Check that a path containing multiple subpaths, in this case two rectangles,
150 // is correctly converted to a NSBezierPath.
151 TEST(CreateNSBezierPathFromSkPathTest, TwoRectanglesPath) {
152 const SkRect rects[] = {
153 {0, 0, 50, 50}, {100, 100, 150, 150},
154 };
155 const NSPoint inside_points[] = {
156 {1, 1}, {1, 49}, {49, 49}, {49, 1}, {101, 101},
157 {101, 149}, {149, 149}, {149, 101}, {25, 25}, {125, 125}};
158 const NSPoint outside_points[] = {{-1, -1}, {-1, 51}, {51, 51}, {51, -1},
159 {99, 99}, {99, 151}, {151, 151}, {151, 99},
160 {75, 75}, {-5, -5}};
161 const size_t kNumPoints = 10;
162 const gfx::Rect expected_bounds(0, 0, 150, 150);
163
164 SkPath path;
165 path.addRect(rects[0]);
166 path.addRect(rects[1]);
167 NSBezierPath* result = CreateNSBezierPathFromSkPath(path);
168
169 // Check points near the boundary of the path and verify that they are
170 // reported correctly as being inside/outside the path.
171 for (size_t i = 0; i < kNumPoints; i++) {
172 EXPECT_TRUE([result containsPoint:inside_points[i]]);
173 EXPECT_FALSE([result containsPoint:outside_points[i]]);
174 }
175
176 // Verify that the bounding box of |result| is correct.
177 EXPECT_EQ(expected_bounds, GetBoundingBox(result));
178 }
179
180 // Test that an SKPath containing a circle is converted correctly to a
181 // NSBezierPath.
182 TEST(CreateNSBezierPathFromSkPathTest, CirclePath) {
183 const int kRadius = 5;
184 const int kCentreX = 10;
185 const int kCentreY = 15;
186 const double kCushion = 0.1;
187 // Expected bounding box of the circle.
188 const gfx::Rect expected_bounds(kCentreX - kRadius, kCentreY - kRadius,
189 2 * kRadius, 2 * kRadius);
190
191 SkPath path;
192 path.addCircle(SkIntToScalar(kCentreX), SkIntToScalar(kCentreY),
193 SkIntToScalar(kRadius));
194 NSBezierPath* const result = CreateNSBezierPathFromSkPath(path);
195
196 // Check points near the boundary of the circle and verify that they are
197 // reported correctly as being inside/outside the path.
198 for (size_t deg = 0; deg < 360; deg++) {
199 NSPoint inside_point =
200 GetRadialPoint(kRadius - kCushion, deg, kCentreX, kCentreY);
201 NSPoint outside_point =
202 GetRadialPoint(kRadius + kCushion, deg, kCentreX, kCentreY);
203 EXPECT_TRUE([result containsPoint:inside_point]);
204 EXPECT_FALSE([result containsPoint:outside_point]);
205 }
206
207 // Check that the returned result has the correct bounding box.
tapted 2016/02/05 04:51:07 maybe mention that this is rounding to whole numbe
karandeepb 2016/02/08 07:47:08 Done.
208 EXPECT_EQ(expected_bounds, GetBoundingBox(result));
209
210 // Check area of converted path is correct upto a certain tolerance value. To
211 // find the area of the NSBezierPath returned, flatten it i.e. convert it to a
212 // polygon.
213 [NSBezierPath setDefaultFlatness:0.01];
214 NSBezierPath* const polygon = [result bezierPathByFlatteningPath];
tapted 2016/02/05 04:51:07 nit: no const
karandeepb 2016/02/08 07:47:08 Done.
215 const double kTolerance = 0.5;
tapted 2016/02/05 04:51:07 Can we tighten this? I guess we should go pretty c
karandeepb 2016/02/08 07:47:09 Done.
216 EXPECT_NEAR(CalculateCircleArea(kRadius), CalculatePolygonArea(polygon),
217 kTolerance);
218 }
219
220 // Test that an SKPath containing a rounded rectangle is converted correctly to
221 // a NSBezierPath.
222 TEST(CreateNSBezierPathFromSkPathTest, RoundedRectanglePath) {
223 const int kRectangleWidth = 50;
224 const int kRectangleHeight = 100;
225 const int kCornerRadius = 5;
226 const double kCushion = 0.1;
227 // Expected bounding box of the rounded rectangle.
228 const gfx::Rect expected_bounds(kRectangleWidth, kRectangleHeight);
229
230 SkRRect rrect;
231 rrect.setRectXY(SkRect::MakeWH(kRectangleWidth, kRectangleHeight),
232 kCornerRadius, kCornerRadius);
233
234 const NSPoint inside_points[] = {
235 // Bottom left corner.
tapted 2016/02/05 04:51:07 nit: remove extra space
karandeepb 2016/02/08 07:47:09 Done.
236 {kCornerRadius, kCornerRadius},
tapted 2016/02/05 04:51:07 maybe half the radius?
karandeepb 2016/02/08 07:47:09 Done.
237 // Bottom right corner.
238 {kRectangleWidth - kCornerRadius, kCornerRadius},
239 // Top Right corner.
240 {kRectangleWidth - kCornerRadius, kRectangleHeight - kCornerRadius},
241 // Top left corner.
242 {kCornerRadius, kRectangleHeight - kCornerRadius},
243 // Bottom middle.
244 {kRectangleWidth / 2.0, kCushion},
245 // Right middle.
246 {kRectangleWidth - kCushion, kRectangleHeight / 2.0},
247 // Top middle.
248 {kRectangleWidth / 2.0, kRectangleHeight - kCushion},
249 // Left middle.
250 {kCushion, kRectangleHeight / 2.0}};
tapted 2016/02/05 04:51:07 nit: }; on a new line? (unless clang format likes
karandeepb 2016/02/08 07:47:09 clang format causes this.
251 const NSPoint outside_points[] = {
252 // Bottom left corner.
253 {0, 0},
254 // Bottom right corner.
255 {kRectangleWidth, 0},
256 // Top right corner.
257 {kRectangleWidth, kRectangleHeight},
258 // Top left corner.
259 {0, kRectangleHeight},
260 // Bottom middle.
261 {kRectangleWidth / 2.0, -kCushion},
262 // Right middle.
263 {kRectangleWidth + kCushion, kRectangleHeight / 2.0},
264 // Top middle.
265 {kRectangleWidth / 2.0, kRectangleHeight + kCushion},
266 // Left middle.
267 {-kCushion, kRectangleHeight / 2.0}};
tapted 2016/02/05 04:51:07 }: -> new line
karandeepb 2016/02/08 07:47:09 clang format causes this.
268 const size_t kNumPoints = 8;
269
270 SkPath path;
271 path.addRRect(rrect);
272 NSBezierPath* const result = CreateNSBezierPathFromSkPath(path);
273
274 // Check points near the boundary of the path and verify that they are
275 // reported correctly as being inside/outside the path.
276 for (size_t i = 0; i < kNumPoints; i++) {
277 EXPECT_TRUE([result containsPoint:inside_points[i]]);
278 EXPECT_FALSE([result containsPoint:outside_points[i]]);
279 }
280
281 // Check that the returned result has the correct bounding box.
282 EXPECT_EQ(expected_bounds, GetBoundingBox(result));
283
284 // Check area of converted path is correct upto a certain tolerance value. To
285 // find the area of the NSBezierPath returned, flatten it i.e. convert it to a
286 // polygon.
287 [NSBezierPath setDefaultFlatness:0.01];
288 NSBezierPath* const polygon = [result bezierPathByFlatteningPath];
289 const double kTolerance = 0.5;
290 EXPECT_NEAR(CalculateRoundedRectangleArea(kRectangleWidth, kRectangleHeight,
291 kCornerRadius),
292 CalculatePolygonArea(polygon), kTolerance);
293 }
294
295 } // namespace gfx
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698