blob: fae2d4b250bf7d3cd8a402a4497d9bd691a638d8 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
reed@android.com3abec1d2009-03-02 05:36:20 +00008#include "Test.h"
reed@google.com55b5f4b2011-09-07 12:23:41 +00009#include "SkPaint.h"
reed@android.com3abec1d2009-03-02 05:36:20 +000010#include "SkPath.h"
reed@google.com04863fa2011-05-15 04:08:24 +000011#include "SkParse.h"
reed@google.com3e71a882012-01-10 18:44:37 +000012#include "SkParsePath.h"
reed@google.com8b06f1a2012-05-29 12:03:46 +000013#include "SkPathEffect.h"
schenney@chromium.org6630d8d2012-01-04 21:05:51 +000014#include "SkRandom.h"
reed@google.com53effc52011-09-21 19:05:12 +000015#include "SkReader32.h"
reed@android.com60bc6d52010-02-11 11:09:39 +000016#include "SkSize.h"
reed@google.com53effc52011-09-21 19:05:12 +000017#include "SkWriter32.h"
reed@android.com3abec1d2009-03-02 05:36:20 +000018
reed@google.com8b06f1a2012-05-29 12:03:46 +000019static void test_strokerec(skiatest::Reporter* reporter) {
20 SkStrokeRec rec(SkStrokeRec::kFill_InitStyle);
21 REPORTER_ASSERT(reporter, rec.isFillStyle());
22
23 rec.setHairlineStyle();
24 REPORTER_ASSERT(reporter, rec.isHairlineStyle());
25
26 rec.setStrokeStyle(SK_Scalar1, false);
27 REPORTER_ASSERT(reporter, SkStrokeRec::kStroke_Style == rec.getStyle());
28
29 rec.setStrokeStyle(SK_Scalar1, true);
30 REPORTER_ASSERT(reporter, SkStrokeRec::kStrokeAndFill_Style == rec.getStyle());
31
32 rec.setStrokeStyle(0, false);
33 REPORTER_ASSERT(reporter, SkStrokeRec::kHairline_Style == rec.getStyle());
34
35 rec.setStrokeStyle(0, true);
36 REPORTER_ASSERT(reporter, SkStrokeRec::kFill_Style == rec.getStyle());
37}
38
bsalomon@google.comf0ed80a2012-02-17 13:38:26 +000039/**
40 * cheapIsDirection can take a shortcut when a path is marked convex.
41 * This function ensures that we always test cheapIsDirection when the path
42 * is flagged with unknown convexity status.
43 */
44static void check_direction(SkPath* path,
45 SkPath::Direction expectedDir,
46 skiatest::Reporter* reporter) {
47 if (SkPath::kConvex_Convexity == path->getConvexity()) {
48 REPORTER_ASSERT(reporter, path->cheapIsDirection(expectedDir));
49 path->setConvexity(SkPath::kUnknown_Convexity);
50 }
51 REPORTER_ASSERT(reporter, path->cheapIsDirection(expectedDir));
52}
53
reed@google.com3e71a882012-01-10 18:44:37 +000054static void test_direction(skiatest::Reporter* reporter) {
55 size_t i;
56 SkPath path;
57 REPORTER_ASSERT(reporter, !path.cheapComputeDirection(NULL));
58 REPORTER_ASSERT(reporter, !path.cheapIsDirection(SkPath::kCW_Direction));
59 REPORTER_ASSERT(reporter, !path.cheapIsDirection(SkPath::kCCW_Direction));
60
61 static const char* gDegen[] = {
62 "M 10 10",
63 "M 10 10 M 20 20",
64 "M 10 10 L 20 20",
65 "M 10 10 L 10 10 L 10 10",
66 "M 10 10 Q 10 10 10 10",
67 "M 10 10 C 10 10 10 10 10 10",
68 };
69 for (i = 0; i < SK_ARRAY_COUNT(gDegen); ++i) {
70 path.reset();
71 bool valid = SkParsePath::FromSVGString(gDegen[i], &path);
72 REPORTER_ASSERT(reporter, valid);
73 REPORTER_ASSERT(reporter, !path.cheapComputeDirection(NULL));
74 }
75
76 static const char* gCW[] = {
reed@google.comcabaf1d2012-01-11 21:03:05 +000077 "M 10 10 L 10 10 Q 20 10 20 20",
reed@google.com3e71a882012-01-10 18:44:37 +000078 "M 10 10 C 20 10 20 20 20 20",
reed@google.comd4146662012-01-31 15:42:29 +000079 "M 20 10 Q 20 20 30 20 L 10 20", // test double-back at y-max
reed@google.com3e71a882012-01-10 18:44:37 +000080 };
81 for (i = 0; i < SK_ARRAY_COUNT(gCW); ++i) {
82 path.reset();
83 bool valid = SkParsePath::FromSVGString(gCW[i], &path);
84 REPORTER_ASSERT(reporter, valid);
bsalomon@google.comf0ed80a2012-02-17 13:38:26 +000085 check_direction(&path, SkPath::kCW_Direction, reporter);
reed@google.com3e71a882012-01-10 18:44:37 +000086 }
87
88 static const char* gCCW[] = {
reed@google.comcabaf1d2012-01-11 21:03:05 +000089 "M 10 10 L 10 10 Q 20 10 20 -20",
reed@google.com3e71a882012-01-10 18:44:37 +000090 "M 10 10 C 20 10 20 -20 20 -20",
reed@google.comd4146662012-01-31 15:42:29 +000091 "M 20 10 Q 20 20 10 20 L 30 20", // test double-back at y-max
reed@google.com3e71a882012-01-10 18:44:37 +000092 };
93 for (i = 0; i < SK_ARRAY_COUNT(gCCW); ++i) {
94 path.reset();
95 bool valid = SkParsePath::FromSVGString(gCCW[i], &path);
96 REPORTER_ASSERT(reporter, valid);
bsalomon@google.comf0ed80a2012-02-17 13:38:26 +000097 check_direction(&path, SkPath::kCCW_Direction, reporter);
reed@google.com3e71a882012-01-10 18:44:37 +000098 }
reed@google.comac8543f2012-01-30 20:51:25 +000099
100 // Test two donuts, each wound a different direction. Only the outer contour
101 // determines the cheap direction
102 path.reset();
103 path.addCircle(0, 0, SkIntToScalar(2), SkPath::kCW_Direction);
104 path.addCircle(0, 0, SkIntToScalar(1), SkPath::kCCW_Direction);
bsalomon@google.comf0ed80a2012-02-17 13:38:26 +0000105 check_direction(&path, SkPath::kCW_Direction, reporter);
106
reed@google.comac8543f2012-01-30 20:51:25 +0000107 path.reset();
108 path.addCircle(0, 0, SkIntToScalar(1), SkPath::kCW_Direction);
109 path.addCircle(0, 0, SkIntToScalar(2), SkPath::kCCW_Direction);
bsalomon@google.comf0ed80a2012-02-17 13:38:26 +0000110 check_direction(&path, SkPath::kCCW_Direction, reporter);
111
bsalomon@google.com6843ac42012-02-17 13:49:03 +0000112#ifdef SK_SCALAR_IS_FLOAT
bsalomon@google.comf0ed80a2012-02-17 13:38:26 +0000113 // triangle with one point really far from the origin.
114 path.reset();
115 // the first point is roughly 1.05e10, 1.05e10
bsalomon@google.com53aab782012-02-23 14:54:49 +0000116 path.moveTo(SkFloatToScalar(SkBits2Float(0x501c7652)), SkFloatToScalar(SkBits2Float(0x501c7652)));
117 path.lineTo(110 * SK_Scalar1, -10 * SK_Scalar1);
118 path.lineTo(-10 * SK_Scalar1, 60 * SK_Scalar1);
119 check_direction(&path, SkPath::kCCW_Direction, reporter);
120#endif
reed@google.com3e71a882012-01-10 18:44:37 +0000121}
122
reed@google.comffdb0182011-11-14 19:29:14 +0000123static void add_rect(SkPath* path, const SkRect& r) {
124 path->moveTo(r.fLeft, r.fTop);
125 path->lineTo(r.fRight, r.fTop);
126 path->lineTo(r.fRight, r.fBottom);
127 path->lineTo(r.fLeft, r.fBottom);
128 path->close();
129}
130
131static void test_bounds(skiatest::Reporter* reporter) {
132 static const SkRect rects[] = {
reed@google.com3563c9e2011-11-14 19:34:57 +0000133 { SkIntToScalar(10), SkIntToScalar(160), SkIntToScalar(610), SkIntToScalar(160) },
134 { SkIntToScalar(610), SkIntToScalar(160), SkIntToScalar(610), SkIntToScalar(199) },
135 { SkIntToScalar(10), SkIntToScalar(198), SkIntToScalar(610), SkIntToScalar(199) },
136 { SkIntToScalar(10), SkIntToScalar(160), SkIntToScalar(10), SkIntToScalar(199) },
reed@google.comffdb0182011-11-14 19:29:14 +0000137 };
138
139 SkPath path0, path1;
140 for (size_t i = 0; i < SK_ARRAY_COUNT(rects); ++i) {
141 path0.addRect(rects[i]);
142 add_rect(&path1, rects[i]);
143 }
144
145 REPORTER_ASSERT(reporter, path0.getBounds() == path1.getBounds());
146}
147
reed@google.com55b5f4b2011-09-07 12:23:41 +0000148static void stroke_cubic(const SkPoint pts[4]) {
149 SkPath path;
150 path.moveTo(pts[0]);
151 path.cubicTo(pts[1], pts[2], pts[3]);
152
153 SkPaint paint;
154 paint.setStyle(SkPaint::kStroke_Style);
155 paint.setStrokeWidth(SK_Scalar1 * 2);
156
157 SkPath fill;
158 paint.getFillPath(path, &fill);
159}
160
161// just ensure this can run w/o any SkASSERTS firing in the debug build
162// we used to assert due to differences in how we determine a degenerate vector
163// but that was fixed with the introduction of SkPoint::CanNormalize
164static void stroke_tiny_cubic() {
165 SkPoint p0[] = {
166 { 372.0f, 92.0f },
167 { 372.0f, 92.0f },
168 { 372.0f, 92.0f },
169 { 372.0f, 92.0f },
170 };
171
172 stroke_cubic(p0);
173
174 SkPoint p1[] = {
175 { 372.0f, 92.0f },
176 { 372.0007f, 92.000755f },
177 { 371.99927f, 92.003922f },
178 { 371.99826f, 92.003899f },
179 };
180
181 stroke_cubic(p1);
182}
183
bsalomon@google.comb3b8dfa2011-07-13 17:44:36 +0000184static void check_close(skiatest::Reporter* reporter, const SkPath& path) {
185 for (int i = 0; i < 2; ++i) {
robertphillips@google.com09042b82012-04-06 20:01:46 +0000186 SkPath::Iter iter(path, SkToBool(i));
bsalomon@google.comb3b8dfa2011-07-13 17:44:36 +0000187 SkPoint mv;
188 SkPoint pts[4];
189 SkPath::Verb v;
190 int nMT = 0;
191 int nCL = 0;
tomhudson@google.com221db3c2011-07-28 21:10:29 +0000192 mv.set(0, 0);
bsalomon@google.comb3b8dfa2011-07-13 17:44:36 +0000193 while (SkPath::kDone_Verb != (v = iter.next(pts))) {
194 switch (v) {
195 case SkPath::kMove_Verb:
196 mv = pts[0];
197 ++nMT;
198 break;
199 case SkPath::kClose_Verb:
200 REPORTER_ASSERT(reporter, mv == pts[0]);
201 ++nCL;
202 break;
203 default:
204 break;
205 }
206 }
207 // if we force a close on the interator we should have a close
208 // for every moveTo
209 REPORTER_ASSERT(reporter, !i || nMT == nCL);
210 }
211}
212
213static void test_close(skiatest::Reporter* reporter) {
214 SkPath closePt;
215 closePt.moveTo(0, 0);
216 closePt.close();
217 check_close(reporter, closePt);
218
219 SkPath openPt;
220 openPt.moveTo(0, 0);
221 check_close(reporter, openPt);
222
223 SkPath empty;
224 check_close(reporter, empty);
225 empty.close();
226 check_close(reporter, empty);
227
228 SkPath rect;
229 rect.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
230 check_close(reporter, rect);
231 rect.close();
232 check_close(reporter, rect);
233
234 SkPath quad;
235 quad.quadTo(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
236 check_close(reporter, quad);
237 quad.close();
238 check_close(reporter, quad);
239
240 SkPath cubic;
241 quad.cubicTo(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1,
242 10*SK_Scalar1, 20 * SK_Scalar1, 20*SK_Scalar1);
243 check_close(reporter, cubic);
244 cubic.close();
245 check_close(reporter, cubic);
246
247 SkPath line;
248 line.moveTo(SK_Scalar1, SK_Scalar1);
249 line.lineTo(10 * SK_Scalar1, 10*SK_Scalar1);
250 check_close(reporter, line);
251 line.close();
252 check_close(reporter, line);
253
254 SkPath rect2;
255 rect2.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
256 rect2.close();
257 rect2.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
258 check_close(reporter, rect2);
259 rect2.close();
260 check_close(reporter, rect2);
261
262 SkPath oval3;
263 oval3.addOval(SkRect::MakeWH(SK_Scalar1*100,SK_Scalar1*100));
264 oval3.close();
265 oval3.addOval(SkRect::MakeWH(SK_Scalar1*200,SK_Scalar1*200));
266 check_close(reporter, oval3);
267 oval3.close();
268 check_close(reporter, oval3);
269
270 SkPath moves;
271 moves.moveTo(SK_Scalar1, SK_Scalar1);
272 moves.moveTo(5 * SK_Scalar1, SK_Scalar1);
273 moves.moveTo(SK_Scalar1, 10 * SK_Scalar1);
274 moves.moveTo(10 *SK_Scalar1, SK_Scalar1);
275 check_close(reporter, moves);
reed@google.com55b5f4b2011-09-07 12:23:41 +0000276
277 stroke_tiny_cubic();
bsalomon@google.comb3b8dfa2011-07-13 17:44:36 +0000278}
279
reed@google.com7c424812011-05-15 04:38:34 +0000280static void check_convexity(skiatest::Reporter* reporter, const SkPath& path,
281 SkPath::Convexity expected) {
282 SkPath::Convexity c = SkPath::ComputeConvexity(path);
283 REPORTER_ASSERT(reporter, c == expected);
284}
285
286static void test_convexity2(skiatest::Reporter* reporter) {
287 SkPath pt;
288 pt.moveTo(0, 0);
289 pt.close();
reed@google.comb54455e2011-05-16 14:16:04 +0000290 check_convexity(reporter, pt, SkPath::kConvex_Convexity);
reed@google.com7c424812011-05-15 04:38:34 +0000291
292 SkPath line;
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000293 line.moveTo(12*SK_Scalar1, 20*SK_Scalar1);
294 line.lineTo(-12*SK_Scalar1, -20*SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000295 line.close();
reed@google.comb54455e2011-05-16 14:16:04 +0000296 check_convexity(reporter, pt, SkPath::kConvex_Convexity);
reed@google.com7c424812011-05-15 04:38:34 +0000297
298 SkPath triLeft;
299 triLeft.moveTo(0, 0);
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000300 triLeft.lineTo(SK_Scalar1, 0);
301 triLeft.lineTo(SK_Scalar1, SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000302 triLeft.close();
303 check_convexity(reporter, triLeft, SkPath::kConvex_Convexity);
304
305 SkPath triRight;
306 triRight.moveTo(0, 0);
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000307 triRight.lineTo(-SK_Scalar1, 0);
308 triRight.lineTo(SK_Scalar1, SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000309 triRight.close();
310 check_convexity(reporter, triRight, SkPath::kConvex_Convexity);
311
312 SkPath square;
313 square.moveTo(0, 0);
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000314 square.lineTo(SK_Scalar1, 0);
315 square.lineTo(SK_Scalar1, SK_Scalar1);
316 square.lineTo(0, SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000317 square.close();
318 check_convexity(reporter, square, SkPath::kConvex_Convexity);
319
320 SkPath redundantSquare;
321 redundantSquare.moveTo(0, 0);
322 redundantSquare.lineTo(0, 0);
323 redundantSquare.lineTo(0, 0);
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000324 redundantSquare.lineTo(SK_Scalar1, 0);
325 redundantSquare.lineTo(SK_Scalar1, 0);
326 redundantSquare.lineTo(SK_Scalar1, 0);
327 redundantSquare.lineTo(SK_Scalar1, SK_Scalar1);
328 redundantSquare.lineTo(SK_Scalar1, SK_Scalar1);
329 redundantSquare.lineTo(SK_Scalar1, SK_Scalar1);
330 redundantSquare.lineTo(0, SK_Scalar1);
331 redundantSquare.lineTo(0, SK_Scalar1);
332 redundantSquare.lineTo(0, SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000333 redundantSquare.close();
334 check_convexity(reporter, redundantSquare, SkPath::kConvex_Convexity);
335
336 SkPath bowTie;
337 bowTie.moveTo(0, 0);
338 bowTie.lineTo(0, 0);
339 bowTie.lineTo(0, 0);
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000340 bowTie.lineTo(SK_Scalar1, SK_Scalar1);
341 bowTie.lineTo(SK_Scalar1, SK_Scalar1);
342 bowTie.lineTo(SK_Scalar1, SK_Scalar1);
343 bowTie.lineTo(SK_Scalar1, 0);
344 bowTie.lineTo(SK_Scalar1, 0);
345 bowTie.lineTo(SK_Scalar1, 0);
346 bowTie.lineTo(0, SK_Scalar1);
347 bowTie.lineTo(0, SK_Scalar1);
348 bowTie.lineTo(0, SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000349 bowTie.close();
350 check_convexity(reporter, bowTie, SkPath::kConcave_Convexity);
351
352 SkPath spiral;
353 spiral.moveTo(0, 0);
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000354 spiral.lineTo(100*SK_Scalar1, 0);
355 spiral.lineTo(100*SK_Scalar1, 100*SK_Scalar1);
356 spiral.lineTo(0, 100*SK_Scalar1);
357 spiral.lineTo(0, 50*SK_Scalar1);
358 spiral.lineTo(50*SK_Scalar1, 50*SK_Scalar1);
359 spiral.lineTo(50*SK_Scalar1, 75*SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000360 spiral.close();
reed@google.com85b6e392011-05-15 20:25:17 +0000361 check_convexity(reporter, spiral, SkPath::kConcave_Convexity);
reed@google.com7c424812011-05-15 04:38:34 +0000362
363 SkPath dent;
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000364 dent.moveTo(0, 0);
365 dent.lineTo(100*SK_Scalar1, 100*SK_Scalar1);
366 dent.lineTo(0, 100*SK_Scalar1);
367 dent.lineTo(-50*SK_Scalar1, 200*SK_Scalar1);
368 dent.lineTo(-200*SK_Scalar1, 100*SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000369 dent.close();
370 check_convexity(reporter, dent, SkPath::kConcave_Convexity);
371}
372
reed@android.com6b82d1a2009-06-03 02:35:01 +0000373static void check_convex_bounds(skiatest::Reporter* reporter, const SkPath& p,
374 const SkRect& bounds) {
375 REPORTER_ASSERT(reporter, p.isConvex());
376 REPORTER_ASSERT(reporter, p.getBounds() == bounds);
reed@google.com62047cf2011-02-07 19:39:09 +0000377
reed@android.com6b82d1a2009-06-03 02:35:01 +0000378 SkPath p2(p);
379 REPORTER_ASSERT(reporter, p2.isConvex());
380 REPORTER_ASSERT(reporter, p2.getBounds() == bounds);
381
382 SkPath other;
383 other.swap(p2);
384 REPORTER_ASSERT(reporter, other.isConvex());
385 REPORTER_ASSERT(reporter, other.getBounds() == bounds);
386}
387
reed@google.com04863fa2011-05-15 04:08:24 +0000388static void setFromString(SkPath* path, const char str[]) {
389 bool first = true;
390 while (str) {
391 SkScalar x, y;
392 str = SkParse::FindScalar(str, &x);
393 if (NULL == str) {
394 break;
395 }
396 str = SkParse::FindScalar(str, &y);
397 SkASSERT(str);
398 if (first) {
399 path->moveTo(x, y);
400 first = false;
401 } else {
402 path->lineTo(x, y);
403 }
404 }
405}
406
407static void test_convexity(skiatest::Reporter* reporter) {
reed@google.com04863fa2011-05-15 04:08:24 +0000408 static const SkPath::Convexity C = SkPath::kConcave_Convexity;
409 static const SkPath::Convexity V = SkPath::kConvex_Convexity;
410
411 SkPath path;
412
reed@google.comb54455e2011-05-16 14:16:04 +0000413 REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
reed@google.come3543972012-01-10 18:59:22 +0000414 path.addCircle(0, 0, SkIntToScalar(10));
reed@google.com04863fa2011-05-15 04:08:24 +0000415 REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
reed@google.come3543972012-01-10 18:59:22 +0000416 path.addCircle(0, 0, SkIntToScalar(10)); // 2nd circle
reed@google.com04863fa2011-05-15 04:08:24 +0000417 REPORTER_ASSERT(reporter, C == SkPath::ComputeConvexity(path));
418 path.reset();
reed@google.come3543972012-01-10 18:59:22 +0000419 path.addRect(0, 0, SkIntToScalar(10), SkIntToScalar(10), SkPath::kCCW_Direction);
reed@google.com04863fa2011-05-15 04:08:24 +0000420 REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
reed@google.com3e71a882012-01-10 18:44:37 +0000421 REPORTER_ASSERT(reporter, path.cheapIsDirection(SkPath::kCCW_Direction));
reed@google.com04863fa2011-05-15 04:08:24 +0000422 path.reset();
reed@google.come3543972012-01-10 18:59:22 +0000423 path.addRect(0, 0, SkIntToScalar(10), SkIntToScalar(10), SkPath::kCW_Direction);
reed@google.com04863fa2011-05-15 04:08:24 +0000424 REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
reed@google.com3e71a882012-01-10 18:44:37 +0000425 REPORTER_ASSERT(reporter, path.cheapIsDirection(SkPath::kCW_Direction));
reed@google.com04863fa2011-05-15 04:08:24 +0000426
427 static const struct {
428 const char* fPathStr;
429 SkPath::Convexity fExpectedConvexity;
430 } gRec[] = {
reed@google.comb54455e2011-05-16 14:16:04 +0000431 { "", SkPath::kConvex_Convexity },
432 { "0 0", SkPath::kConvex_Convexity },
433 { "0 0 10 10", SkPath::kConvex_Convexity },
reed@google.com85b6e392011-05-15 20:25:17 +0000434 { "0 0 10 10 20 20 0 0 10 10", SkPath::kConcave_Convexity },
reed@google.com04863fa2011-05-15 04:08:24 +0000435 { "0 0 10 10 10 20", SkPath::kConvex_Convexity },
436 { "0 0 10 10 10 0", SkPath::kConvex_Convexity },
437 { "0 0 10 10 10 0 0 10", SkPath::kConcave_Convexity },
438 { "0 0 10 0 0 10 -10 -10", SkPath::kConcave_Convexity },
439 };
440
441 for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
442 SkPath path;
443 setFromString(&path, gRec[i].fPathStr);
444 SkPath::Convexity c = SkPath::ComputeConvexity(path);
445 REPORTER_ASSERT(reporter, c == gRec[i].fExpectedConvexity);
446 }
447}
448
reed@google.com7e6c4d12012-05-10 14:05:43 +0000449static void test_isLine(skiatest::Reporter* reporter) {
450 SkPath path;
451 SkPoint pts[2];
452 const SkScalar value = SkIntToScalar(5);
453
454 REPORTER_ASSERT(reporter, !path.isLine(NULL));
455
456 // set some non-zero values
457 pts[0].set(value, value);
458 pts[1].set(value, value);
459 REPORTER_ASSERT(reporter, !path.isLine(pts));
460 // check that pts was untouched
461 REPORTER_ASSERT(reporter, pts[0].equals(value, value));
462 REPORTER_ASSERT(reporter, pts[1].equals(value, value));
463
464 const SkScalar moveX = SkIntToScalar(1);
465 const SkScalar moveY = SkIntToScalar(2);
466 SkASSERT(value != moveX && value != moveY);
467
468 path.moveTo(moveX, moveY);
469 REPORTER_ASSERT(reporter, !path.isLine(NULL));
470 REPORTER_ASSERT(reporter, !path.isLine(pts));
471 // check that pts was untouched
472 REPORTER_ASSERT(reporter, pts[0].equals(value, value));
473 REPORTER_ASSERT(reporter, pts[1].equals(value, value));
474
475 const SkScalar lineX = SkIntToScalar(2);
476 const SkScalar lineY = SkIntToScalar(2);
477 SkASSERT(value != lineX && value != lineY);
478
479 path.lineTo(lineX, lineY);
480 REPORTER_ASSERT(reporter, path.isLine(NULL));
481
482 REPORTER_ASSERT(reporter, !pts[0].equals(moveX, moveY));
483 REPORTER_ASSERT(reporter, !pts[1].equals(lineX, lineY));
484 REPORTER_ASSERT(reporter, path.isLine(pts));
485 REPORTER_ASSERT(reporter, pts[0].equals(moveX, moveY));
486 REPORTER_ASSERT(reporter, pts[1].equals(lineX, lineY));
487
488 path.lineTo(0, 0); // too many points/verbs
489 REPORTER_ASSERT(reporter, !path.isLine(NULL));
490 REPORTER_ASSERT(reporter, !path.isLine(pts));
491 REPORTER_ASSERT(reporter, pts[0].equals(moveX, moveY));
492 REPORTER_ASSERT(reporter, pts[1].equals(lineX, lineY));
493}
494
caryclark@google.comf1316942011-07-26 19:54:45 +0000495// Simple isRect test is inline TestPath, below.
496// test_isRect provides more extensive testing.
497static void test_isRect(skiatest::Reporter* reporter) {
498 // passing tests (all moveTo / lineTo...
499 SkPoint r1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
500 SkPoint r2[] = {{1, 0}, {1, 1}, {0, 1}, {0, 0}};
501 SkPoint r3[] = {{1, 1}, {0, 1}, {0, 0}, {1, 0}};
502 SkPoint r4[] = {{0, 1}, {0, 0}, {1, 0}, {1, 1}};
503 SkPoint r5[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}};
504 SkPoint r6[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
505 SkPoint r7[] = {{1, 1}, {1, 0}, {0, 0}, {0, 1}};
506 SkPoint r8[] = {{1, 0}, {0, 0}, {0, 1}, {1, 1}};
507 SkPoint r9[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
508 SkPoint ra[] = {{0, 0}, {0, .5f}, {0, 1}, {.5f, 1}, {1, 1}, {1, .5f},
509 {1, 0}, {.5f, 0}};
510 SkPoint rb[] = {{0, 0}, {.5f, 0}, {1, 0}, {1, .5f}, {1, 1}, {.5f, 1},
511 {0, 1}, {0, .5f}};
512 SkPoint rc[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}};
513 SkPoint rd[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}};
514 SkPoint re[] = {{0, 0}, {1, 0}, {1, 0}, {1, 1}, {0, 1}};
515
516 // failing tests
517 SkPoint f1[] = {{0, 0}, {1, 0}, {1, 1}}; // too few points
518 SkPoint f2[] = {{0, 0}, {1, 1}, {0, 1}, {1, 0}}; // diagonal
519 SkPoint f3[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}, {1, 0}}; // wraps
520 SkPoint f4[] = {{0, 0}, {1, 0}, {0, 0}, {1, 0}, {1, 1}, {0, 1}}; // backs up
521 SkPoint f5[] = {{0, 0}, {1, 0}, {1, 1}, {2, 0}}; // end overshoots
522 SkPoint f6[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 2}}; // end overshoots
523 SkPoint f7[] = {{0, 0}, {1, 0}, {1, 1}, {0, 2}}; // end overshoots
524 SkPoint f8[] = {{0, 0}, {1, 0}, {1, 1}, {1, 0}}; // 'L'
525
526 // failing, no close
527 SkPoint c1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}}; // close doesn't match
528 SkPoint c2[] = {{0, 0}, {1, 0}, {1, 2}, {0, 2}, {0, 1}}; // ditto
529
530 size_t testLen[] = {
531 sizeof(r1), sizeof(r2), sizeof(r3), sizeof(r4), sizeof(r5), sizeof(r6),
532 sizeof(r7), sizeof(r8), sizeof(r9), sizeof(ra), sizeof(rb), sizeof(rc),
533 sizeof(rd), sizeof(re),
534 sizeof(f1), sizeof(f2), sizeof(f3), sizeof(f4), sizeof(f5), sizeof(f6),
535 sizeof(f7), sizeof(f8),
536 sizeof(c1), sizeof(c2)
537 };
538 SkPoint* tests[] = {
539 r1, r2, r3, r4, r5, r6, r7, r8, r9, ra, rb, rc, rd, re,
540 f1, f2, f3, f4, f5, f6, f7, f8,
541 c1, c2
542 };
543 SkPoint* lastPass = re;
544 SkPoint* lastClose = f8;
545 bool fail = false;
546 bool close = true;
547 const size_t testCount = sizeof(tests) / sizeof(tests[0]);
548 size_t index;
549 for (size_t testIndex = 0; testIndex < testCount; ++testIndex) {
550 SkPath path;
551 path.moveTo(tests[testIndex][0].fX, tests[testIndex][0].fY);
552 for (index = 1; index < testLen[testIndex] / sizeof(SkPoint); ++index) {
553 path.lineTo(tests[testIndex][index].fX, tests[testIndex][index].fY);
554 }
555 if (close) {
556 path.close();
557 }
558 REPORTER_ASSERT(reporter, fail ^ path.isRect(0));
559 if (tests[testIndex] == lastPass) {
560 fail = true;
561 }
562 if (tests[testIndex] == lastClose) {
563 close = false;
564 }
565 }
566
567 // fail, close then line
568 SkPath path1;
569 path1.moveTo(r1[0].fX, r1[0].fY);
570 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
571 path1.lineTo(r1[index].fX, r1[index].fY);
572 }
573 path1.close();
574 path1.lineTo(1, 0);
575 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
576
577 // fail, move in the middle
578 path1.reset();
579 path1.moveTo(r1[0].fX, r1[0].fY);
580 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
581 if (index == 2) {
582 path1.moveTo(1, .5f);
583 }
584 path1.lineTo(r1[index].fX, r1[index].fY);
585 }
586 path1.close();
587 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
588
589 // fail, move on the edge
590 path1.reset();
591 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
592 path1.moveTo(r1[index - 1].fX, r1[index - 1].fY);
593 path1.lineTo(r1[index].fX, r1[index].fY);
594 }
595 path1.close();
596 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
597
598 // fail, quad
599 path1.reset();
600 path1.moveTo(r1[0].fX, r1[0].fY);
601 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
602 if (index == 2) {
603 path1.quadTo(1, .5f, 1, .5f);
604 }
605 path1.lineTo(r1[index].fX, r1[index].fY);
606 }
607 path1.close();
608 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
609
610 // fail, cubic
611 path1.reset();
612 path1.moveTo(r1[0].fX, r1[0].fY);
613 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
614 if (index == 2) {
615 path1.cubicTo(1, .5f, 1, .5f, 1, .5f);
616 }
617 path1.lineTo(r1[index].fX, r1[index].fY);
618 }
619 path1.close();
620 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
621}
622
reed@google.com53effc52011-09-21 19:05:12 +0000623static void test_flattening(skiatest::Reporter* reporter) {
624 SkPath p;
625
626 static const SkPoint pts[] = {
627 { 0, 0 },
628 { SkIntToScalar(10), SkIntToScalar(10) },
629 { SkIntToScalar(20), SkIntToScalar(10) }, { SkIntToScalar(20), 0 },
630 { 0, 0 }, { 0, SkIntToScalar(10) }, { SkIntToScalar(1), SkIntToScalar(10) }
631 };
632 p.moveTo(pts[0]);
633 p.lineTo(pts[1]);
634 p.quadTo(pts[2], pts[3]);
635 p.cubicTo(pts[4], pts[5], pts[6]);
636
637 SkWriter32 writer(100);
638 p.flatten(writer);
639 size_t size = writer.size();
640 SkAutoMalloc storage(size);
641 writer.flatten(storage.get());
642 SkReader32 reader(storage.get(), size);
643
644 SkPath p1;
645 REPORTER_ASSERT(reporter, p1 != p);
646 p1.unflatten(reader);
647 REPORTER_ASSERT(reporter, p1 == p);
648}
649
650static void test_transform(skiatest::Reporter* reporter) {
651 SkPath p, p1;
652
653 static const SkPoint pts[] = {
654 { 0, 0 },
655 { SkIntToScalar(10), SkIntToScalar(10) },
656 { SkIntToScalar(20), SkIntToScalar(10) }, { SkIntToScalar(20), 0 },
657 { 0, 0 }, { 0, SkIntToScalar(10) }, { SkIntToScalar(1), SkIntToScalar(10) }
658 };
659 p.moveTo(pts[0]);
660 p.lineTo(pts[1]);
661 p.quadTo(pts[2], pts[3]);
662 p.cubicTo(pts[4], pts[5], pts[6]);
663
664 SkMatrix matrix;
665 matrix.reset();
666 p.transform(matrix, &p1);
667 REPORTER_ASSERT(reporter, p == p1);
668
669 matrix.setScale(SK_Scalar1 * 2, SK_Scalar1 * 3);
670 p.transform(matrix, &p1);
671 SkPoint pts1[7];
672 int count = p1.getPoints(pts1, 7);
673 REPORTER_ASSERT(reporter, 7 == count);
674 for (int i = 0; i < count; ++i) {
675 SkPoint newPt = SkPoint::Make(pts[i].fX * 2, pts[i].fY * 3);
676 REPORTER_ASSERT(reporter, newPt == pts1[i]);
677 }
678}
679
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000680static void test_zero_length_paths(skiatest::Reporter* reporter) {
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000681 SkPath p;
682 SkPoint pt;
683 SkRect bounds;
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000684
685 // Lone moveTo case
686 p.moveTo(SK_Scalar1, SK_Scalar1);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000687 REPORTER_ASSERT(reporter, !p.isEmpty());
688 REPORTER_ASSERT(reporter, 1 == p.countPoints());
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000689 p.getLastPt(&pt);
690 REPORTER_ASSERT(reporter, pt.fX == SK_Scalar1);
691 REPORTER_ASSERT(reporter, pt.fY == SK_Scalar1);
692 bounds.set(0, 0, 0, 0);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000693 REPORTER_ASSERT(reporter, bounds == p.getBounds());
694
695 // MoveTo-MoveTo case
696 p.moveTo(SK_Scalar1*2, SK_Scalar1);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000697 REPORTER_ASSERT(reporter, !p.isEmpty());
698 REPORTER_ASSERT(reporter, 2 == p.countPoints());
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000699 p.getLastPt(&pt);
700 REPORTER_ASSERT(reporter, pt.fX == SK_Scalar1*2);
701 REPORTER_ASSERT(reporter, pt.fY == SK_Scalar1);
702 bounds.set(SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000703 REPORTER_ASSERT(reporter, bounds == p.getBounds());
704
705 // moveTo-close case
706 p.reset();
707 p.moveTo(SK_Scalar1, SK_Scalar1);
708 p.close();
709 bounds.set(0, 0, 0, 0);
710 REPORTER_ASSERT(reporter, !p.isEmpty());
711 REPORTER_ASSERT(reporter, 1 == p.countPoints());
712 REPORTER_ASSERT(reporter, bounds == p.getBounds());
713
714 // moveTo-close-moveTo-close case
715 p.moveTo(SK_Scalar1*2, SK_Scalar1);
716 p.close();
schenney@chromium.org32879492011-12-20 15:33:11 +0000717 bounds.set(SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000718 REPORTER_ASSERT(reporter, !p.isEmpty());
719 REPORTER_ASSERT(reporter, 2 == p.countPoints());
720 REPORTER_ASSERT(reporter, bounds == p.getBounds());
721
722 // moveTo-line case
723 p.reset();
724 p.moveTo(SK_Scalar1, SK_Scalar1);
725 p.lineTo(SK_Scalar1, SK_Scalar1);
726 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
727 REPORTER_ASSERT(reporter, !p.isEmpty());
728 REPORTER_ASSERT(reporter, 2 == p.countPoints());
729 REPORTER_ASSERT(reporter, bounds == p.getBounds());
730
731 // moveTo-lineTo-moveTo-lineTo case
732 p.moveTo(SK_Scalar1*2, SK_Scalar1);
733 p.lineTo(SK_Scalar1*2, SK_Scalar1);
734 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
735 REPORTER_ASSERT(reporter, !p.isEmpty());
736 REPORTER_ASSERT(reporter, 4 == p.countPoints());
737 REPORTER_ASSERT(reporter, bounds == p.getBounds());
738
739 // moveTo-line-close case
740 p.reset();
741 p.moveTo(SK_Scalar1, SK_Scalar1);
742 p.lineTo(SK_Scalar1, SK_Scalar1);
743 p.close();
744 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
745 REPORTER_ASSERT(reporter, !p.isEmpty());
746 REPORTER_ASSERT(reporter, 2 == p.countPoints());
747 REPORTER_ASSERT(reporter, bounds == p.getBounds());
748
749 // moveTo-line-close-moveTo-line-close case
750 p.moveTo(SK_Scalar1*2, SK_Scalar1);
751 p.lineTo(SK_Scalar1*2, SK_Scalar1);
752 p.close();
753 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
754 REPORTER_ASSERT(reporter, !p.isEmpty());
755 REPORTER_ASSERT(reporter, 4 == p.countPoints());
756 REPORTER_ASSERT(reporter, bounds == p.getBounds());
757
758 // moveTo-quadTo case
759 p.reset();
760 p.moveTo(SK_Scalar1, SK_Scalar1);
761 p.quadTo(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
762 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
763 REPORTER_ASSERT(reporter, !p.isEmpty());
764 REPORTER_ASSERT(reporter, 3 == p.countPoints());
765 REPORTER_ASSERT(reporter, bounds == p.getBounds());
766
767 // moveTo-quadTo-close case
768 p.close();
769 REPORTER_ASSERT(reporter, !p.isEmpty());
770 REPORTER_ASSERT(reporter, 3 == p.countPoints());
771 REPORTER_ASSERT(reporter, bounds == p.getBounds());
772
773 // moveTo-quadTo-moveTo-quadTo case
774 p.reset();
775 p.moveTo(SK_Scalar1, SK_Scalar1);
776 p.quadTo(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
777 p.moveTo(SK_Scalar1*2, SK_Scalar1);
778 p.quadTo(SK_Scalar1*2, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
779 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
780 REPORTER_ASSERT(reporter, !p.isEmpty());
781 REPORTER_ASSERT(reporter, 6 == p.countPoints());
782 REPORTER_ASSERT(reporter, bounds == p.getBounds());
783
784 // moveTo-cubicTo case
785 p.reset();
786 p.moveTo(SK_Scalar1, SK_Scalar1);
787 p.cubicTo(SK_Scalar1, SK_Scalar1,
788 SK_Scalar1, SK_Scalar1,
789 SK_Scalar1, SK_Scalar1);
790 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
791 REPORTER_ASSERT(reporter, !p.isEmpty());
792 REPORTER_ASSERT(reporter, 4 == p.countPoints());
793 REPORTER_ASSERT(reporter, bounds == p.getBounds());
794
795 // moveTo-quadTo-close case
796 p.close();
797 REPORTER_ASSERT(reporter, !p.isEmpty());
798 REPORTER_ASSERT(reporter, 4 == p.countPoints());
799 REPORTER_ASSERT(reporter, bounds == p.getBounds());
800
801 // moveTo-quadTo-moveTo-quadTo case
802 p.reset();
803 p.moveTo(SK_Scalar1, SK_Scalar1);
804 p.cubicTo(SK_Scalar1, SK_Scalar1,
805 SK_Scalar1, SK_Scalar1,
806 SK_Scalar1, SK_Scalar1);
807 p.moveTo(SK_Scalar1*2, SK_Scalar1);
808 p.cubicTo(SK_Scalar1*2, SK_Scalar1,
809 SK_Scalar1*2, SK_Scalar1,
810 SK_Scalar1*2, SK_Scalar1);
811 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
812 REPORTER_ASSERT(reporter, !p.isEmpty());
813 REPORTER_ASSERT(reporter, 8 == p.countPoints());
814 REPORTER_ASSERT(reporter, bounds == p.getBounds());
815}
816
817struct SegmentInfo {
818 SkPath fPath;
819 int fPointCount;
820};
821
reed@google.com10296cc2011-09-21 12:29:05 +0000822#define kCurveSegmentMask (SkPath::kQuad_SegmentMask | SkPath::kCubic_SegmentMask)
823
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000824static void test_segment_masks(skiatest::Reporter* reporter) {
825 SkPath p;
826 p.moveTo(0, 0);
827 p.quadTo(100, 100, 200, 200);
828 REPORTER_ASSERT(reporter, SkPath::kQuad_SegmentMask == p.getSegmentMasks());
829 REPORTER_ASSERT(reporter, !p.isEmpty());
830 p.cubicTo(100, 100, 200, 200, 300, 300);
831 REPORTER_ASSERT(reporter, kCurveSegmentMask == p.getSegmentMasks());
832 REPORTER_ASSERT(reporter, !p.isEmpty());
833 p.reset();
834 p.moveTo(0, 0);
835 p.cubicTo(100, 100, 200, 200, 300, 300);
836 REPORTER_ASSERT(reporter, SkPath::kCubic_SegmentMask == p.getSegmentMasks());
837 REPORTER_ASSERT(reporter, !p.isEmpty());
838}
839
840static void test_iter(skiatest::Reporter* reporter) {
841 SkPath p;
842 SkPoint pts[4];
843
844 // Test an iterator with no path
845 SkPath::Iter noPathIter;
846 REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
847 // Test that setting an empty path works
848 noPathIter.setPath(p, false);
849 REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
850 // Test that close path makes no difference for an empty path
851 noPathIter.setPath(p, true);
852 REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
853
854 // Test an iterator with an initial empty path
855 SkPath::Iter iter(p, false);
856 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
857
858 // Test that close path makes no difference
859 SkPath::Iter forceCloseIter(p, true);
860 REPORTER_ASSERT(reporter, forceCloseIter.next(pts) == SkPath::kDone_Verb);
861
862 // Test that a move-only path produces nothing when iterated.
863 p.moveTo(SK_Scalar1, 0);
864 iter.setPath(p, false);
865 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
866
867 // No matter how many moves we add, we should still get nothing back.
868 p.moveTo(SK_Scalar1*2, 0);
869 p.moveTo(SK_Scalar1*3, 0);
870 p.moveTo(SK_Scalar1*4, 0);
871 p.moveTo(SK_Scalar1*5, 0);
872 iter.setPath(p, false);
873 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
874
875 // Nor should force closing
876 forceCloseIter.setPath(p, true);
877 REPORTER_ASSERT(reporter, forceCloseIter.next(pts) == SkPath::kDone_Verb);
878
879 // Initial closes should be ignored
880 p.reset();
881 p.close();
882 iter.setPath(p, false);
883 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
884 // Even if force closed
885 forceCloseIter.setPath(p, true);
886 REPORTER_ASSERT(reporter, forceCloseIter.next(pts) == SkPath::kDone_Verb);
887
888 // Move/close sequences should also be ignored
889 p.reset();
890 p.close();
891 p.moveTo(SK_Scalar1, 0);
892 p.close();
893 p.close();
894 p.moveTo(SK_Scalar1*2, 0);
895 p.close();
896 p.moveTo(SK_Scalar1*3, 0);
897 p.moveTo(SK_Scalar1*4, 0);
898 p.close();
899 iter.setPath(p, false);
900 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
901 // Even if force closed
902 forceCloseIter.setPath(p, true);
903 REPORTER_ASSERT(reporter, forceCloseIter.next(pts) == SkPath::kDone_Verb);
904
905 // The GM degeneratesegments.cpp test is more extensive
906}
907
908static void test_raw_iter(skiatest::Reporter* reporter) {
909 SkPath p;
910 SkPoint pts[4];
911
912 // Test an iterator with no path
913 SkPath::RawIter noPathIter;
914 REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
915 // Test that setting an empty path works
916 noPathIter.setPath(p);
917 REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
918
919 // Test an iterator with an initial empty path
920 SkPath::RawIter iter(p);
921 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
922
923 // Test that a move-only path returns the move.
924 p.moveTo(SK_Scalar1, 0);
925 iter.setPath(p);
926 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
927 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
928 REPORTER_ASSERT(reporter, pts[0].fY == 0);
929 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
930
931 // No matter how many moves we add, we should get them all back
932 p.moveTo(SK_Scalar1*2, SK_Scalar1);
933 p.moveTo(SK_Scalar1*3, SK_Scalar1*2);
934 iter.setPath(p);
935 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
936 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
937 REPORTER_ASSERT(reporter, pts[0].fY == 0);
938 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
939 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2);
940 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1);
941 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
942 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*3);
943 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*2);
944 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
945
946 // Initial close is never ever stored
947 p.reset();
948 p.close();
949 iter.setPath(p);
950 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
951
952 // Move/close sequences
953 p.reset();
954 p.close(); // Not stored, no purpose
955 p.moveTo(SK_Scalar1, 0);
956 p.close();
957 p.close(); // Not stored, no purpose
958 p.moveTo(SK_Scalar1*2, SK_Scalar1);
959 p.close();
960 p.moveTo(SK_Scalar1*3, SK_Scalar1*2);
961 p.moveTo(SK_Scalar1*4, SK_Scalar1*3);
962 p.close();
963 iter.setPath(p);
964 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
965 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
966 REPORTER_ASSERT(reporter, pts[0].fY == 0);
967 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kClose_Verb);
968 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
969 REPORTER_ASSERT(reporter, pts[0].fY == 0);
970 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
971 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2);
972 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1);
973 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kClose_Verb);
974 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2);
975 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1);
976 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
977 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*3);
978 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*2);
979 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
980 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*4);
981 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*3);
982 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kClose_Verb);
983 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*4);
984 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*3);
985 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
986
987 // Generate random paths and verify
988 SkPoint randomPts[25];
989 for (int i = 0; i < 5; ++i) {
990 for (int j = 0; j < 5; ++j) {
991 randomPts[i*5+j].set(SK_Scalar1*i, SK_Scalar1*j);
992 }
993 }
994
995 // Max of 10 segments, max 3 points per segment
996 SkRandom rand(9876543);
997 SkPoint expectedPts[31]; // May have leading moveTo
reed@google.comd335d1d2012-01-12 18:17:11 +0000998 SkPath::Verb expectedVerbs[22]; // May have leading moveTo
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000999 SkPath::Verb nextVerb;
reed@google.comd335d1d2012-01-12 18:17:11 +00001000
schenney@chromium.org6630d8d2012-01-04 21:05:51 +00001001 for (int i = 0; i < 500; ++i) {
1002 p.reset();
1003 bool lastWasClose = true;
1004 bool haveMoveTo = false;
reed@google.comd335d1d2012-01-12 18:17:11 +00001005 SkPoint lastMoveToPt = { 0, 0 };
schenney@chromium.org6630d8d2012-01-04 21:05:51 +00001006 int numPoints = 0;
1007 int numVerbs = (rand.nextU() >> 16) % 10;
1008 int numIterVerbs = 0;
1009 for (int j = 0; j < numVerbs; ++j) {
1010 do {
1011 nextVerb = static_cast<SkPath::Verb>((rand.nextU() >> 16) % SkPath::kDone_Verb);
1012 } while (lastWasClose && nextVerb == SkPath::kClose_Verb);
schenney@chromium.org6630d8d2012-01-04 21:05:51 +00001013 switch (nextVerb) {
1014 case SkPath::kMove_Verb:
1015 expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
1016 p.moveTo(expectedPts[numPoints]);
reed@google.comd335d1d2012-01-12 18:17:11 +00001017 lastMoveToPt = expectedPts[numPoints];
schenney@chromium.org6630d8d2012-01-04 21:05:51 +00001018 numPoints += 1;
1019 lastWasClose = false;
1020 haveMoveTo = true;
1021 break;
1022 case SkPath::kLine_Verb:
1023 if (!haveMoveTo) {
reed@google.comd335d1d2012-01-12 18:17:11 +00001024 expectedPts[numPoints++] = lastMoveToPt;
schenney@chromium.org6630d8d2012-01-04 21:05:51 +00001025 expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
1026 haveMoveTo = true;
1027 }
1028 expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
1029 p.lineTo(expectedPts[numPoints]);
1030 numPoints += 1;
1031 lastWasClose = false;
1032 break;
1033 case SkPath::kQuad_Verb:
1034 if (!haveMoveTo) {
reed@google.comd335d1d2012-01-12 18:17:11 +00001035 expectedPts[numPoints++] = lastMoveToPt;
schenney@chromium.org6630d8d2012-01-04 21:05:51 +00001036 expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
1037 haveMoveTo = true;
1038 }
1039 expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
1040 expectedPts[numPoints + 1] = randomPts[(rand.nextU() >> 16) % 25];
1041 p.quadTo(expectedPts[numPoints], expectedPts[numPoints + 1]);
1042 numPoints += 2;
1043 lastWasClose = false;
1044 break;
1045 case SkPath::kCubic_Verb:
1046 if (!haveMoveTo) {
reed@google.comd335d1d2012-01-12 18:17:11 +00001047 expectedPts[numPoints++] = lastMoveToPt;
schenney@chromium.org6630d8d2012-01-04 21:05:51 +00001048 expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
1049 haveMoveTo = true;
1050 }
1051 expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
1052 expectedPts[numPoints + 1] = randomPts[(rand.nextU() >> 16) % 25];
1053 expectedPts[numPoints + 2] = randomPts[(rand.nextU() >> 16) % 25];
1054 p.cubicTo(expectedPts[numPoints], expectedPts[numPoints + 1],
1055 expectedPts[numPoints + 2]);
1056 numPoints += 3;
1057 lastWasClose = false;
1058 break;
1059 case SkPath::kClose_Verb:
1060 p.close();
reed@google.comd335d1d2012-01-12 18:17:11 +00001061 haveMoveTo = false;
schenney@chromium.org6630d8d2012-01-04 21:05:51 +00001062 lastWasClose = true;
1063 break;
1064 default:;
1065 }
1066 expectedVerbs[numIterVerbs++] = nextVerb;
1067 }
1068
1069 iter.setPath(p);
1070 numVerbs = numIterVerbs;
1071 numIterVerbs = 0;
1072 int numIterPts = 0;
1073 SkPoint lastMoveTo;
1074 SkPoint lastPt;
1075 lastMoveTo.set(0, 0);
1076 lastPt.set(0, 0);
1077 while ((nextVerb = iter.next(pts)) != SkPath::kDone_Verb) {
1078 REPORTER_ASSERT(reporter, nextVerb == expectedVerbs[numIterVerbs]);
1079 numIterVerbs++;
1080 switch (nextVerb) {
1081 case SkPath::kMove_Verb:
1082 REPORTER_ASSERT(reporter, numIterPts < numPoints);
1083 REPORTER_ASSERT(reporter, pts[0] == expectedPts[numIterPts]);
1084 lastPt = lastMoveTo = pts[0];
1085 numIterPts += 1;
1086 break;
1087 case SkPath::kLine_Verb:
1088 REPORTER_ASSERT(reporter, numIterPts < numPoints + 1);
1089 REPORTER_ASSERT(reporter, pts[0] == lastPt);
1090 REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]);
1091 lastPt = pts[1];
1092 numIterPts += 1;
1093 break;
1094 case SkPath::kQuad_Verb:
1095 REPORTER_ASSERT(reporter, numIterPts < numPoints + 2);
1096 REPORTER_ASSERT(reporter, pts[0] == lastPt);
1097 REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]);
1098 REPORTER_ASSERT(reporter, pts[2] == expectedPts[numIterPts + 1]);
1099 lastPt = pts[2];
1100 numIterPts += 2;
1101 break;
1102 case SkPath::kCubic_Verb:
1103 REPORTER_ASSERT(reporter, numIterPts < numPoints + 3);
1104 REPORTER_ASSERT(reporter, pts[0] == lastPt);
1105 REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]);
1106 REPORTER_ASSERT(reporter, pts[2] == expectedPts[numIterPts + 1]);
1107 REPORTER_ASSERT(reporter, pts[3] == expectedPts[numIterPts + 2]);
1108 lastPt = pts[3];
1109 numIterPts += 3;
1110 break;
1111 case SkPath::kClose_Verb:
1112 REPORTER_ASSERT(reporter, pts[0] == lastMoveTo);
1113 lastPt = lastMoveTo;
1114 break;
1115 default:;
1116 }
1117 }
1118 REPORTER_ASSERT(reporter, numIterPts == numPoints);
1119 REPORTER_ASSERT(reporter, numIterVerbs == numVerbs);
1120 }
1121}
1122
bsalomon@google.com6aa29652012-04-18 13:29:52 +00001123static void check_for_circle(skiatest::Reporter* reporter,
1124 const SkPath& path, bool expected) {
1125 SkRect rect;
1126 REPORTER_ASSERT(reporter, path.isOval(&rect) == expected);
1127 if (expected) {
1128 REPORTER_ASSERT(reporter, rect.height() == rect.width());
1129 }
1130}
1131
1132static void test_circle_skew(skiatest::Reporter* reporter,
1133 const SkPath& path) {
1134 SkPath tmp;
1135
1136 SkMatrix m;
1137 m.setSkew(SkIntToScalar(3), SkIntToScalar(5));
1138 path.transform(m, &tmp);
1139 check_for_circle(reporter, tmp, false);
1140}
1141
1142static void test_circle_translate(skiatest::Reporter* reporter,
1143 const SkPath& path) {
1144 SkPath tmp;
1145
1146 // translate at small offset
1147 SkMatrix m;
1148 m.setTranslate(SkIntToScalar(15), SkIntToScalar(15));
1149 path.transform(m, &tmp);
1150 check_for_circle(reporter, tmp, true);
1151
1152 tmp.reset();
1153 m.reset();
1154
1155 // translate at a relatively big offset
1156 m.setTranslate(SkIntToScalar(1000), SkIntToScalar(1000));
1157 path.transform(m, &tmp);
1158 check_for_circle(reporter, tmp, true);
1159}
1160
1161static void test_circle_rotate(skiatest::Reporter* reporter,
1162 const SkPath& path) {
1163 for (int angle = 0; angle < 360; ++angle) {
1164 SkPath tmp;
1165 SkMatrix m;
1166 m.setRotate(SkIntToScalar(angle));
1167 path.transform(m, &tmp);
1168
1169 // TODO: a rotated circle whose rotated angle is not a mutiple of 90
1170 // degrees is not an oval anymore, this can be improved. we made this
1171 // for the simplicity of our implementation.
1172 if (angle % 90 == 0) {
1173 check_for_circle(reporter, tmp, true);
1174 } else {
1175 check_for_circle(reporter, tmp, false);
1176 }
1177 }
1178}
1179
1180static void test_circle_with_direction(skiatest::Reporter* reporter,
1181 SkPath::Direction dir) {
1182 SkPath path;
1183
1184 // circle at origin
1185 path.addCircle(0, 0, SkIntToScalar(20), dir);
1186 check_for_circle(reporter, path, true);
1187 test_circle_rotate(reporter, path);
1188 test_circle_translate(reporter, path);
1189 test_circle_skew(reporter, path);
1190
1191 // circle at an offset at (10, 10)
1192 path.reset();
1193 path.addCircle(SkIntToScalar(10), SkIntToScalar(10),
1194 SkIntToScalar(20), dir);
1195 check_for_circle(reporter, path, true);
1196 test_circle_rotate(reporter, path);
1197 test_circle_translate(reporter, path);
1198 test_circle_skew(reporter, path);
1199}
1200
1201static void test_circle_with_add_paths(skiatest::Reporter* reporter) {
1202 SkPath path;
1203 SkPath circle;
1204 SkPath rect;
1205 SkPath empty;
1206
1207 circle.addCircle(0, 0, SkIntToScalar(10), SkPath::kCW_Direction);
1208 rect.addRect(SkIntToScalar(5), SkIntToScalar(5),
1209 SkIntToScalar(20), SkIntToScalar(20), SkPath::kCW_Direction);
1210
1211 SkMatrix translate;
1212 translate.setTranslate(SkIntToScalar(12), SkIntToScalar(12));
1213
1214 // For simplicity, all the path concatenation related operations
1215 // would mark it non-circle, though in theory it's still a circle.
1216
1217 // empty + circle (translate)
1218 path = empty;
1219 path.addPath(circle, translate);
1220 check_for_circle(reporter, path, false);
1221
1222 // circle + empty (translate)
1223 path = circle;
1224 path.addPath(empty, translate);
1225 check_for_circle(reporter, path, false);
1226
1227 // test reverseAddPath
1228 path = circle;
1229 path.reverseAddPath(rect);
1230 check_for_circle(reporter, path, false);
1231}
1232
1233static void test_circle(skiatest::Reporter* reporter) {
1234 test_circle_with_direction(reporter, SkPath::kCW_Direction);
1235 test_circle_with_direction(reporter, SkPath::kCCW_Direction);
1236
1237 // multiple addCircle()
1238 SkPath path;
1239 path.addCircle(0, 0, SkIntToScalar(10), SkPath::kCW_Direction);
1240 path.addCircle(0, 0, SkIntToScalar(20), SkPath::kCW_Direction);
1241 check_for_circle(reporter, path, false);
1242
1243 // some extra lineTo() would make isOval() fail
1244 path.reset();
1245 path.addCircle(0, 0, SkIntToScalar(10), SkPath::kCW_Direction);
1246 path.lineTo(0, 0);
1247 check_for_circle(reporter, path, false);
1248
1249 // not back to the original point
1250 path.reset();
1251 path.addCircle(0, 0, SkIntToScalar(10), SkPath::kCW_Direction);
1252 path.setLastPt(SkIntToScalar(5), SkIntToScalar(5));
1253 check_for_circle(reporter, path, false);
1254
1255 test_circle_with_add_paths(reporter);
1256}
1257
1258static void test_oval(skiatest::Reporter* reporter) {
1259 SkRect rect;
1260 SkMatrix m;
1261 SkPath path;
1262
1263 rect = SkRect::MakeWH(SkIntToScalar(30), SkIntToScalar(50));
1264 path.addOval(rect);
1265
1266 REPORTER_ASSERT(reporter, path.isOval(NULL));
1267
1268 m.setRotate(SkIntToScalar(90));
1269 SkPath tmp;
1270 path.transform(m, &tmp);
1271 // an oval rotated 90 degrees is still an oval.
1272 REPORTER_ASSERT(reporter, tmp.isOval(NULL));
1273
1274 m.reset();
1275 m.setRotate(SkIntToScalar(30));
1276 tmp.reset();
1277 path.transform(m, &tmp);
1278 // an oval rotated 30 degrees is not an oval anymore.
1279 REPORTER_ASSERT(reporter, !tmp.isOval(NULL));
1280
1281 // since empty path being transformed.
1282 path.reset();
1283 tmp.reset();
1284 m.reset();
1285 path.transform(m, &tmp);
1286 REPORTER_ASSERT(reporter, !tmp.isOval(NULL));
1287
1288 // empty path is not an oval
1289 tmp.reset();
1290 REPORTER_ASSERT(reporter, !tmp.isOval(NULL));
1291
1292 // only has moveTo()s
1293 tmp.reset();
1294 tmp.moveTo(0, 0);
1295 tmp.moveTo(SkIntToScalar(10), SkIntToScalar(10));
1296 REPORTER_ASSERT(reporter, !tmp.isOval(NULL));
1297
1298 // mimic WebKit's calling convention,
1299 // call moveTo() first and then call addOval()
1300 path.reset();
1301 path.moveTo(0, 0);
1302 path.addOval(rect);
1303 REPORTER_ASSERT(reporter, path.isOval(NULL));
1304
1305 // copy path
1306 path.reset();
1307 tmp.reset();
1308 tmp.addOval(rect);
1309 path = tmp;
1310 REPORTER_ASSERT(reporter, path.isOval(NULL));
1311}
1312
reed@google.com04863fa2011-05-15 04:08:24 +00001313void TestPath(skiatest::Reporter* reporter) {
reed@android.com60bc6d52010-02-11 11:09:39 +00001314 {
1315 SkSize size;
1316 size.fWidth = 3.4f;
1317 size.width();
1318 size = SkSize::Make(3,4);
1319 SkISize isize = SkISize::Make(3,4);
1320 }
1321
1322 SkTSize<SkScalar>::Make(3,4);
1323
reed@android.com3abec1d2009-03-02 05:36:20 +00001324 SkPath p, p2;
1325 SkRect bounds, bounds2;
reed@android.com80e39a72009-04-02 16:59:40 +00001326
reed@android.com3abec1d2009-03-02 05:36:20 +00001327 REPORTER_ASSERT(reporter, p.isEmpty());
schenney@chromium.org4da06ab2011-12-20 15:14:18 +00001328 REPORTER_ASSERT(reporter, 0 == p.countPoints());
reed@google.com10296cc2011-09-21 12:29:05 +00001329 REPORTER_ASSERT(reporter, 0 == p.getSegmentMasks());
reed@google.comb54455e2011-05-16 14:16:04 +00001330 REPORTER_ASSERT(reporter, p.isConvex());
reed@android.com3abec1d2009-03-02 05:36:20 +00001331 REPORTER_ASSERT(reporter, p.getFillType() == SkPath::kWinding_FillType);
1332 REPORTER_ASSERT(reporter, !p.isInverseFillType());
1333 REPORTER_ASSERT(reporter, p == p2);
1334 REPORTER_ASSERT(reporter, !(p != p2));
1335
reed@android.comd252db02009-04-01 18:31:44 +00001336 REPORTER_ASSERT(reporter, p.getBounds().isEmpty());
reed@android.com80e39a72009-04-02 16:59:40 +00001337
reed@android.com3abec1d2009-03-02 05:36:20 +00001338 bounds.set(0, 0, SK_Scalar1, SK_Scalar1);
reed@android.com6b82d1a2009-06-03 02:35:01 +00001339
reed@android.com6b82d1a2009-06-03 02:35:01 +00001340 p.addRoundRect(bounds, SK_Scalar1, SK_Scalar1);
1341 check_convex_bounds(reporter, p, bounds);
reed@google.com10296cc2011-09-21 12:29:05 +00001342 // we have quads or cubics
1343 REPORTER_ASSERT(reporter, p.getSegmentMasks() & kCurveSegmentMask);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +00001344 REPORTER_ASSERT(reporter, !p.isEmpty());
reed@google.com62047cf2011-02-07 19:39:09 +00001345
reed@android.com6b82d1a2009-06-03 02:35:01 +00001346 p.reset();
reed@google.com10296cc2011-09-21 12:29:05 +00001347 REPORTER_ASSERT(reporter, 0 == p.getSegmentMasks());
schenney@chromium.org4da06ab2011-12-20 15:14:18 +00001348 REPORTER_ASSERT(reporter, p.isEmpty());
reed@google.com10296cc2011-09-21 12:29:05 +00001349
reed@android.com6b82d1a2009-06-03 02:35:01 +00001350 p.addOval(bounds);
1351 check_convex_bounds(reporter, p, bounds);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +00001352 REPORTER_ASSERT(reporter, !p.isEmpty());
reed@google.com62047cf2011-02-07 19:39:09 +00001353
reed@android.com6b82d1a2009-06-03 02:35:01 +00001354 p.reset();
reed@android.com3abec1d2009-03-02 05:36:20 +00001355 p.addRect(bounds);
reed@android.com6b82d1a2009-06-03 02:35:01 +00001356 check_convex_bounds(reporter, p, bounds);
reed@google.com10296cc2011-09-21 12:29:05 +00001357 // we have only lines
1358 REPORTER_ASSERT(reporter, SkPath::kLine_SegmentMask == p.getSegmentMasks());
schenney@chromium.org4da06ab2011-12-20 15:14:18 +00001359 REPORTER_ASSERT(reporter, !p.isEmpty());
reed@android.com3abec1d2009-03-02 05:36:20 +00001360
1361 REPORTER_ASSERT(reporter, p != p2);
1362 REPORTER_ASSERT(reporter, !(p == p2));
1363
1364 // does getPoints return the right result
1365 REPORTER_ASSERT(reporter, p.getPoints(NULL, 5) == 4);
1366 SkPoint pts[4];
1367 int count = p.getPoints(pts, 4);
1368 REPORTER_ASSERT(reporter, count == 4);
1369 bounds2.set(pts, 4);
1370 REPORTER_ASSERT(reporter, bounds == bounds2);
reed@android.com80e39a72009-04-02 16:59:40 +00001371
reed@android.com3abec1d2009-03-02 05:36:20 +00001372 bounds.offset(SK_Scalar1*3, SK_Scalar1*4);
1373 p.offset(SK_Scalar1*3, SK_Scalar1*4);
reed@android.comd252db02009-04-01 18:31:44 +00001374 REPORTER_ASSERT(reporter, bounds == p.getBounds());
reed@android.com3abec1d2009-03-02 05:36:20 +00001375
reed@android.com3abec1d2009-03-02 05:36:20 +00001376 REPORTER_ASSERT(reporter, p.isRect(NULL));
caryclark@google.comf1316942011-07-26 19:54:45 +00001377 bounds2.setEmpty();
reed@android.com3abec1d2009-03-02 05:36:20 +00001378 REPORTER_ASSERT(reporter, p.isRect(&bounds2));
1379 REPORTER_ASSERT(reporter, bounds == bounds2);
reed@android.com80e39a72009-04-02 16:59:40 +00001380
reed@android.com3abec1d2009-03-02 05:36:20 +00001381 // now force p to not be a rect
1382 bounds.set(0, 0, SK_Scalar1/2, SK_Scalar1/2);
1383 p.addRect(bounds);
1384 REPORTER_ASSERT(reporter, !p.isRect(NULL));
reed@android.com3abec1d2009-03-02 05:36:20 +00001385
reed@google.com7e6c4d12012-05-10 14:05:43 +00001386 test_isLine(reporter);
1387 test_isRect(reporter);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +00001388 test_zero_length_paths(reporter);
reed@google.comcabaf1d2012-01-11 21:03:05 +00001389 test_direction(reporter);
reed@google.com04863fa2011-05-15 04:08:24 +00001390 test_convexity(reporter);
reed@google.com7c424812011-05-15 04:38:34 +00001391 test_convexity2(reporter);
bsalomon@google.comb3b8dfa2011-07-13 17:44:36 +00001392 test_close(reporter);
schenney@chromium.org6630d8d2012-01-04 21:05:51 +00001393 test_segment_masks(reporter);
reed@google.com53effc52011-09-21 19:05:12 +00001394 test_flattening(reporter);
1395 test_transform(reporter);
reed@google.com3563c9e2011-11-14 19:34:57 +00001396 test_bounds(reporter);
schenney@chromium.org6630d8d2012-01-04 21:05:51 +00001397 test_iter(reporter);
1398 test_raw_iter(reporter);
bsalomon@google.com6aa29652012-04-18 13:29:52 +00001399 test_circle(reporter);
1400 test_oval(reporter);
reed@google.com8b06f1a2012-05-29 12:03:46 +00001401
1402 test_strokerec(reporter);
reed@android.com3abec1d2009-03-02 05:36:20 +00001403}
1404
1405#include "TestClassDef.h"
1406DEFINE_TESTCLASS("Path", PathTestClass, TestPath)