blob: 73bdef0802f412bec26e53d7c2d5b301fedaa955 [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.com744faba2012-05-29 19:54:52 +000019// assert that we always
20// start with a moveTo
21// only have 1 moveTo
22// only have Lines after that
23// end with a single close
24// only have (at most) 1 close
25//
26static void test_poly(skiatest::Reporter* reporter, const SkPath& path,
27 const SkPoint srcPts[], int count, bool expectClose) {
28 SkPath::RawIter iter(path);
29 SkPoint pts[4];
reed@google.com744faba2012-05-29 19:54:52 +000030
31 bool firstTime = true;
32 bool foundClose = false;
33 for (;;) {
34 switch (iter.next(pts)) {
35 case SkPath::kMove_Verb:
36 REPORTER_ASSERT(reporter, firstTime);
37 REPORTER_ASSERT(reporter, pts[0] == srcPts[0]);
38 srcPts++;
39 firstTime = false;
40 break;
41 case SkPath::kLine_Verb:
42 REPORTER_ASSERT(reporter, !firstTime);
43 REPORTER_ASSERT(reporter, pts[1] == srcPts[0]);
44 srcPts++;
45 break;
46 case SkPath::kQuad_Verb:
47 REPORTER_ASSERT(reporter, !"unexpected quad verb");
48 break;
49 case SkPath::kCubic_Verb:
50 REPORTER_ASSERT(reporter, !"unexpected cubic verb");
51 break;
52 case SkPath::kClose_Verb:
53 REPORTER_ASSERT(reporter, !firstTime);
54 REPORTER_ASSERT(reporter, !foundClose);
55 REPORTER_ASSERT(reporter, expectClose);
56 foundClose = true;
57 break;
58 case SkPath::kDone_Verb:
59 goto DONE;
60 }
61 }
62DONE:
63 REPORTER_ASSERT(reporter, foundClose == expectClose);
64}
65
66static void test_addPoly(skiatest::Reporter* reporter) {
67 SkPoint pts[32];
68 SkRandom rand;
69
70 for (size_t i = 0; i < SK_ARRAY_COUNT(pts); ++i) {
71 pts[i].fX = rand.nextSScalar1();
72 pts[i].fY = rand.nextSScalar1();
73 }
74
75 for (int doClose = 0; doClose <= 1; ++doClose) {
76 for (size_t count = 1; count <= SK_ARRAY_COUNT(pts); ++count) {
77 SkPath path;
78 path.addPoly(pts, count, SkToBool(doClose));
79 test_poly(reporter, path, pts, count, SkToBool(doClose));
80 }
81 }
82}
83
reed@google.com8b06f1a2012-05-29 12:03:46 +000084static void test_strokerec(skiatest::Reporter* reporter) {
85 SkStrokeRec rec(SkStrokeRec::kFill_InitStyle);
86 REPORTER_ASSERT(reporter, rec.isFillStyle());
87
88 rec.setHairlineStyle();
89 REPORTER_ASSERT(reporter, rec.isHairlineStyle());
90
91 rec.setStrokeStyle(SK_Scalar1, false);
92 REPORTER_ASSERT(reporter, SkStrokeRec::kStroke_Style == rec.getStyle());
93
94 rec.setStrokeStyle(SK_Scalar1, true);
95 REPORTER_ASSERT(reporter, SkStrokeRec::kStrokeAndFill_Style == rec.getStyle());
96
97 rec.setStrokeStyle(0, false);
98 REPORTER_ASSERT(reporter, SkStrokeRec::kHairline_Style == rec.getStyle());
99
100 rec.setStrokeStyle(0, true);
101 REPORTER_ASSERT(reporter, SkStrokeRec::kFill_Style == rec.getStyle());
102}
103
bsalomon@google.comf0ed80a2012-02-17 13:38:26 +0000104/**
105 * cheapIsDirection can take a shortcut when a path is marked convex.
106 * This function ensures that we always test cheapIsDirection when the path
107 * is flagged with unknown convexity status.
108 */
109static void check_direction(SkPath* path,
110 SkPath::Direction expectedDir,
111 skiatest::Reporter* reporter) {
112 if (SkPath::kConvex_Convexity == path->getConvexity()) {
113 REPORTER_ASSERT(reporter, path->cheapIsDirection(expectedDir));
114 path->setConvexity(SkPath::kUnknown_Convexity);
115 }
116 REPORTER_ASSERT(reporter, path->cheapIsDirection(expectedDir));
117}
118
reed@google.com3e71a882012-01-10 18:44:37 +0000119static void test_direction(skiatest::Reporter* reporter) {
120 size_t i;
121 SkPath path;
122 REPORTER_ASSERT(reporter, !path.cheapComputeDirection(NULL));
123 REPORTER_ASSERT(reporter, !path.cheapIsDirection(SkPath::kCW_Direction));
124 REPORTER_ASSERT(reporter, !path.cheapIsDirection(SkPath::kCCW_Direction));
125
126 static const char* gDegen[] = {
127 "M 10 10",
128 "M 10 10 M 20 20",
129 "M 10 10 L 20 20",
130 "M 10 10 L 10 10 L 10 10",
131 "M 10 10 Q 10 10 10 10",
132 "M 10 10 C 10 10 10 10 10 10",
133 };
134 for (i = 0; i < SK_ARRAY_COUNT(gDegen); ++i) {
135 path.reset();
136 bool valid = SkParsePath::FromSVGString(gDegen[i], &path);
137 REPORTER_ASSERT(reporter, valid);
138 REPORTER_ASSERT(reporter, !path.cheapComputeDirection(NULL));
139 }
140
141 static const char* gCW[] = {
reed@google.comcabaf1d2012-01-11 21:03:05 +0000142 "M 10 10 L 10 10 Q 20 10 20 20",
reed@google.com3e71a882012-01-10 18:44:37 +0000143 "M 10 10 C 20 10 20 20 20 20",
reed@google.comd4146662012-01-31 15:42:29 +0000144 "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 +0000145 };
146 for (i = 0; i < SK_ARRAY_COUNT(gCW); ++i) {
147 path.reset();
148 bool valid = SkParsePath::FromSVGString(gCW[i], &path);
149 REPORTER_ASSERT(reporter, valid);
bsalomon@google.comf0ed80a2012-02-17 13:38:26 +0000150 check_direction(&path, SkPath::kCW_Direction, reporter);
reed@google.com3e71a882012-01-10 18:44:37 +0000151 }
152
153 static const char* gCCW[] = {
reed@google.comcabaf1d2012-01-11 21:03:05 +0000154 "M 10 10 L 10 10 Q 20 10 20 -20",
reed@google.com3e71a882012-01-10 18:44:37 +0000155 "M 10 10 C 20 10 20 -20 20 -20",
reed@google.comd4146662012-01-31 15:42:29 +0000156 "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 +0000157 };
158 for (i = 0; i < SK_ARRAY_COUNT(gCCW); ++i) {
159 path.reset();
160 bool valid = SkParsePath::FromSVGString(gCCW[i], &path);
161 REPORTER_ASSERT(reporter, valid);
bsalomon@google.comf0ed80a2012-02-17 13:38:26 +0000162 check_direction(&path, SkPath::kCCW_Direction, reporter);
reed@google.com3e71a882012-01-10 18:44:37 +0000163 }
reed@google.comac8543f2012-01-30 20:51:25 +0000164
165 // Test two donuts, each wound a different direction. Only the outer contour
166 // determines the cheap direction
167 path.reset();
168 path.addCircle(0, 0, SkIntToScalar(2), SkPath::kCW_Direction);
169 path.addCircle(0, 0, SkIntToScalar(1), SkPath::kCCW_Direction);
bsalomon@google.comf0ed80a2012-02-17 13:38:26 +0000170 check_direction(&path, SkPath::kCW_Direction, reporter);
171
reed@google.comac8543f2012-01-30 20:51:25 +0000172 path.reset();
173 path.addCircle(0, 0, SkIntToScalar(1), SkPath::kCW_Direction);
174 path.addCircle(0, 0, SkIntToScalar(2), SkPath::kCCW_Direction);
bsalomon@google.comf0ed80a2012-02-17 13:38:26 +0000175 check_direction(&path, SkPath::kCCW_Direction, reporter);
176
bsalomon@google.com6843ac42012-02-17 13:49:03 +0000177#ifdef SK_SCALAR_IS_FLOAT
bsalomon@google.comf0ed80a2012-02-17 13:38:26 +0000178 // triangle with one point really far from the origin.
179 path.reset();
180 // the first point is roughly 1.05e10, 1.05e10
bsalomon@google.com53aab782012-02-23 14:54:49 +0000181 path.moveTo(SkFloatToScalar(SkBits2Float(0x501c7652)), SkFloatToScalar(SkBits2Float(0x501c7652)));
182 path.lineTo(110 * SK_Scalar1, -10 * SK_Scalar1);
183 path.lineTo(-10 * SK_Scalar1, 60 * SK_Scalar1);
184 check_direction(&path, SkPath::kCCW_Direction, reporter);
185#endif
reed@google.com3e71a882012-01-10 18:44:37 +0000186}
187
reed@google.comffdb0182011-11-14 19:29:14 +0000188static void add_rect(SkPath* path, const SkRect& r) {
189 path->moveTo(r.fLeft, r.fTop);
190 path->lineTo(r.fRight, r.fTop);
191 path->lineTo(r.fRight, r.fBottom);
192 path->lineTo(r.fLeft, r.fBottom);
193 path->close();
194}
195
196static void test_bounds(skiatest::Reporter* reporter) {
197 static const SkRect rects[] = {
reed@google.com3563c9e2011-11-14 19:34:57 +0000198 { SkIntToScalar(10), SkIntToScalar(160), SkIntToScalar(610), SkIntToScalar(160) },
199 { SkIntToScalar(610), SkIntToScalar(160), SkIntToScalar(610), SkIntToScalar(199) },
200 { SkIntToScalar(10), SkIntToScalar(198), SkIntToScalar(610), SkIntToScalar(199) },
201 { SkIntToScalar(10), SkIntToScalar(160), SkIntToScalar(10), SkIntToScalar(199) },
reed@google.comffdb0182011-11-14 19:29:14 +0000202 };
203
204 SkPath path0, path1;
205 for (size_t i = 0; i < SK_ARRAY_COUNT(rects); ++i) {
206 path0.addRect(rects[i]);
207 add_rect(&path1, rects[i]);
208 }
209
210 REPORTER_ASSERT(reporter, path0.getBounds() == path1.getBounds());
211}
212
reed@google.com55b5f4b2011-09-07 12:23:41 +0000213static void stroke_cubic(const SkPoint pts[4]) {
214 SkPath path;
215 path.moveTo(pts[0]);
216 path.cubicTo(pts[1], pts[2], pts[3]);
217
218 SkPaint paint;
219 paint.setStyle(SkPaint::kStroke_Style);
220 paint.setStrokeWidth(SK_Scalar1 * 2);
221
222 SkPath fill;
223 paint.getFillPath(path, &fill);
224}
225
226// just ensure this can run w/o any SkASSERTS firing in the debug build
227// we used to assert due to differences in how we determine a degenerate vector
228// but that was fixed with the introduction of SkPoint::CanNormalize
229static void stroke_tiny_cubic() {
230 SkPoint p0[] = {
231 { 372.0f, 92.0f },
232 { 372.0f, 92.0f },
233 { 372.0f, 92.0f },
234 { 372.0f, 92.0f },
235 };
236
237 stroke_cubic(p0);
238
239 SkPoint p1[] = {
240 { 372.0f, 92.0f },
241 { 372.0007f, 92.000755f },
242 { 371.99927f, 92.003922f },
243 { 371.99826f, 92.003899f },
244 };
245
246 stroke_cubic(p1);
247}
248
bsalomon@google.comb3b8dfa2011-07-13 17:44:36 +0000249static void check_close(skiatest::Reporter* reporter, const SkPath& path) {
250 for (int i = 0; i < 2; ++i) {
robertphillips@google.com09042b82012-04-06 20:01:46 +0000251 SkPath::Iter iter(path, SkToBool(i));
bsalomon@google.comb3b8dfa2011-07-13 17:44:36 +0000252 SkPoint mv;
253 SkPoint pts[4];
254 SkPath::Verb v;
255 int nMT = 0;
256 int nCL = 0;
tomhudson@google.com221db3c2011-07-28 21:10:29 +0000257 mv.set(0, 0);
bsalomon@google.comb3b8dfa2011-07-13 17:44:36 +0000258 while (SkPath::kDone_Verb != (v = iter.next(pts))) {
259 switch (v) {
260 case SkPath::kMove_Verb:
261 mv = pts[0];
262 ++nMT;
263 break;
264 case SkPath::kClose_Verb:
265 REPORTER_ASSERT(reporter, mv == pts[0]);
266 ++nCL;
267 break;
268 default:
269 break;
270 }
271 }
272 // if we force a close on the interator we should have a close
273 // for every moveTo
274 REPORTER_ASSERT(reporter, !i || nMT == nCL);
275 }
276}
277
278static void test_close(skiatest::Reporter* reporter) {
279 SkPath closePt;
280 closePt.moveTo(0, 0);
281 closePt.close();
282 check_close(reporter, closePt);
283
284 SkPath openPt;
285 openPt.moveTo(0, 0);
286 check_close(reporter, openPt);
287
288 SkPath empty;
289 check_close(reporter, empty);
290 empty.close();
291 check_close(reporter, empty);
292
293 SkPath rect;
294 rect.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
295 check_close(reporter, rect);
296 rect.close();
297 check_close(reporter, rect);
298
299 SkPath quad;
300 quad.quadTo(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
301 check_close(reporter, quad);
302 quad.close();
303 check_close(reporter, quad);
304
305 SkPath cubic;
306 quad.cubicTo(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1,
307 10*SK_Scalar1, 20 * SK_Scalar1, 20*SK_Scalar1);
308 check_close(reporter, cubic);
309 cubic.close();
310 check_close(reporter, cubic);
311
312 SkPath line;
313 line.moveTo(SK_Scalar1, SK_Scalar1);
314 line.lineTo(10 * SK_Scalar1, 10*SK_Scalar1);
315 check_close(reporter, line);
316 line.close();
317 check_close(reporter, line);
318
319 SkPath rect2;
320 rect2.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
321 rect2.close();
322 rect2.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
323 check_close(reporter, rect2);
324 rect2.close();
325 check_close(reporter, rect2);
326
327 SkPath oval3;
328 oval3.addOval(SkRect::MakeWH(SK_Scalar1*100,SK_Scalar1*100));
329 oval3.close();
330 oval3.addOval(SkRect::MakeWH(SK_Scalar1*200,SK_Scalar1*200));
331 check_close(reporter, oval3);
332 oval3.close();
333 check_close(reporter, oval3);
334
335 SkPath moves;
336 moves.moveTo(SK_Scalar1, SK_Scalar1);
337 moves.moveTo(5 * SK_Scalar1, SK_Scalar1);
338 moves.moveTo(SK_Scalar1, 10 * SK_Scalar1);
339 moves.moveTo(10 *SK_Scalar1, SK_Scalar1);
340 check_close(reporter, moves);
reed@google.com55b5f4b2011-09-07 12:23:41 +0000341
342 stroke_tiny_cubic();
bsalomon@google.comb3b8dfa2011-07-13 17:44:36 +0000343}
344
reed@google.com7c424812011-05-15 04:38:34 +0000345static void check_convexity(skiatest::Reporter* reporter, const SkPath& path,
346 SkPath::Convexity expected) {
347 SkPath::Convexity c = SkPath::ComputeConvexity(path);
348 REPORTER_ASSERT(reporter, c == expected);
349}
350
351static void test_convexity2(skiatest::Reporter* reporter) {
352 SkPath pt;
353 pt.moveTo(0, 0);
354 pt.close();
reed@google.comb54455e2011-05-16 14:16:04 +0000355 check_convexity(reporter, pt, SkPath::kConvex_Convexity);
reed@google.com7c424812011-05-15 04:38:34 +0000356
357 SkPath line;
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000358 line.moveTo(12*SK_Scalar1, 20*SK_Scalar1);
359 line.lineTo(-12*SK_Scalar1, -20*SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000360 line.close();
reed@google.comb54455e2011-05-16 14:16:04 +0000361 check_convexity(reporter, pt, SkPath::kConvex_Convexity);
reed@google.com7c424812011-05-15 04:38:34 +0000362
363 SkPath triLeft;
364 triLeft.moveTo(0, 0);
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000365 triLeft.lineTo(SK_Scalar1, 0);
366 triLeft.lineTo(SK_Scalar1, SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000367 triLeft.close();
368 check_convexity(reporter, triLeft, SkPath::kConvex_Convexity);
369
370 SkPath triRight;
371 triRight.moveTo(0, 0);
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000372 triRight.lineTo(-SK_Scalar1, 0);
373 triRight.lineTo(SK_Scalar1, SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000374 triRight.close();
375 check_convexity(reporter, triRight, SkPath::kConvex_Convexity);
376
377 SkPath square;
378 square.moveTo(0, 0);
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000379 square.lineTo(SK_Scalar1, 0);
380 square.lineTo(SK_Scalar1, SK_Scalar1);
381 square.lineTo(0, SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000382 square.close();
383 check_convexity(reporter, square, SkPath::kConvex_Convexity);
384
385 SkPath redundantSquare;
386 redundantSquare.moveTo(0, 0);
387 redundantSquare.lineTo(0, 0);
388 redundantSquare.lineTo(0, 0);
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000389 redundantSquare.lineTo(SK_Scalar1, 0);
390 redundantSquare.lineTo(SK_Scalar1, 0);
391 redundantSquare.lineTo(SK_Scalar1, 0);
392 redundantSquare.lineTo(SK_Scalar1, SK_Scalar1);
393 redundantSquare.lineTo(SK_Scalar1, SK_Scalar1);
394 redundantSquare.lineTo(SK_Scalar1, SK_Scalar1);
395 redundantSquare.lineTo(0, SK_Scalar1);
396 redundantSquare.lineTo(0, SK_Scalar1);
397 redundantSquare.lineTo(0, SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000398 redundantSquare.close();
399 check_convexity(reporter, redundantSquare, SkPath::kConvex_Convexity);
400
401 SkPath bowTie;
402 bowTie.moveTo(0, 0);
403 bowTie.lineTo(0, 0);
404 bowTie.lineTo(0, 0);
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000405 bowTie.lineTo(SK_Scalar1, SK_Scalar1);
406 bowTie.lineTo(SK_Scalar1, SK_Scalar1);
407 bowTie.lineTo(SK_Scalar1, SK_Scalar1);
408 bowTie.lineTo(SK_Scalar1, 0);
409 bowTie.lineTo(SK_Scalar1, 0);
410 bowTie.lineTo(SK_Scalar1, 0);
411 bowTie.lineTo(0, SK_Scalar1);
412 bowTie.lineTo(0, SK_Scalar1);
413 bowTie.lineTo(0, SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000414 bowTie.close();
415 check_convexity(reporter, bowTie, SkPath::kConcave_Convexity);
416
417 SkPath spiral;
418 spiral.moveTo(0, 0);
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000419 spiral.lineTo(100*SK_Scalar1, 0);
420 spiral.lineTo(100*SK_Scalar1, 100*SK_Scalar1);
421 spiral.lineTo(0, 100*SK_Scalar1);
422 spiral.lineTo(0, 50*SK_Scalar1);
423 spiral.lineTo(50*SK_Scalar1, 50*SK_Scalar1);
424 spiral.lineTo(50*SK_Scalar1, 75*SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000425 spiral.close();
reed@google.com85b6e392011-05-15 20:25:17 +0000426 check_convexity(reporter, spiral, SkPath::kConcave_Convexity);
reed@google.com7c424812011-05-15 04:38:34 +0000427
428 SkPath dent;
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000429 dent.moveTo(0, 0);
430 dent.lineTo(100*SK_Scalar1, 100*SK_Scalar1);
431 dent.lineTo(0, 100*SK_Scalar1);
432 dent.lineTo(-50*SK_Scalar1, 200*SK_Scalar1);
433 dent.lineTo(-200*SK_Scalar1, 100*SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000434 dent.close();
435 check_convexity(reporter, dent, SkPath::kConcave_Convexity);
436}
437
reed@android.com6b82d1a2009-06-03 02:35:01 +0000438static void check_convex_bounds(skiatest::Reporter* reporter, const SkPath& p,
439 const SkRect& bounds) {
440 REPORTER_ASSERT(reporter, p.isConvex());
441 REPORTER_ASSERT(reporter, p.getBounds() == bounds);
reed@google.com62047cf2011-02-07 19:39:09 +0000442
reed@android.com6b82d1a2009-06-03 02:35:01 +0000443 SkPath p2(p);
444 REPORTER_ASSERT(reporter, p2.isConvex());
445 REPORTER_ASSERT(reporter, p2.getBounds() == bounds);
446
447 SkPath other;
448 other.swap(p2);
449 REPORTER_ASSERT(reporter, other.isConvex());
450 REPORTER_ASSERT(reporter, other.getBounds() == bounds);
451}
452
reed@google.com04863fa2011-05-15 04:08:24 +0000453static void setFromString(SkPath* path, const char str[]) {
454 bool first = true;
455 while (str) {
456 SkScalar x, y;
457 str = SkParse::FindScalar(str, &x);
458 if (NULL == str) {
459 break;
460 }
461 str = SkParse::FindScalar(str, &y);
462 SkASSERT(str);
463 if (first) {
464 path->moveTo(x, y);
465 first = false;
466 } else {
467 path->lineTo(x, y);
468 }
469 }
470}
471
472static void test_convexity(skiatest::Reporter* reporter) {
reed@google.com04863fa2011-05-15 04:08:24 +0000473 static const SkPath::Convexity C = SkPath::kConcave_Convexity;
474 static const SkPath::Convexity V = SkPath::kConvex_Convexity;
475
476 SkPath path;
477
reed@google.comb54455e2011-05-16 14:16:04 +0000478 REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
reed@google.come3543972012-01-10 18:59:22 +0000479 path.addCircle(0, 0, SkIntToScalar(10));
reed@google.com04863fa2011-05-15 04:08:24 +0000480 REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
reed@google.come3543972012-01-10 18:59:22 +0000481 path.addCircle(0, 0, SkIntToScalar(10)); // 2nd circle
reed@google.com04863fa2011-05-15 04:08:24 +0000482 REPORTER_ASSERT(reporter, C == SkPath::ComputeConvexity(path));
483 path.reset();
reed@google.come3543972012-01-10 18:59:22 +0000484 path.addRect(0, 0, SkIntToScalar(10), SkIntToScalar(10), SkPath::kCCW_Direction);
reed@google.com04863fa2011-05-15 04:08:24 +0000485 REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
reed@google.com3e71a882012-01-10 18:44:37 +0000486 REPORTER_ASSERT(reporter, path.cheapIsDirection(SkPath::kCCW_Direction));
reed@google.com04863fa2011-05-15 04:08:24 +0000487 path.reset();
reed@google.come3543972012-01-10 18:59:22 +0000488 path.addRect(0, 0, SkIntToScalar(10), SkIntToScalar(10), SkPath::kCW_Direction);
reed@google.com04863fa2011-05-15 04:08:24 +0000489 REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
reed@google.com3e71a882012-01-10 18:44:37 +0000490 REPORTER_ASSERT(reporter, path.cheapIsDirection(SkPath::kCW_Direction));
reed@google.com04863fa2011-05-15 04:08:24 +0000491
492 static const struct {
493 const char* fPathStr;
494 SkPath::Convexity fExpectedConvexity;
495 } gRec[] = {
reed@google.comb54455e2011-05-16 14:16:04 +0000496 { "", SkPath::kConvex_Convexity },
497 { "0 0", SkPath::kConvex_Convexity },
498 { "0 0 10 10", SkPath::kConvex_Convexity },
reed@google.com85b6e392011-05-15 20:25:17 +0000499 { "0 0 10 10 20 20 0 0 10 10", SkPath::kConcave_Convexity },
reed@google.com04863fa2011-05-15 04:08:24 +0000500 { "0 0 10 10 10 20", SkPath::kConvex_Convexity },
501 { "0 0 10 10 10 0", SkPath::kConvex_Convexity },
502 { "0 0 10 10 10 0 0 10", SkPath::kConcave_Convexity },
503 { "0 0 10 0 0 10 -10 -10", SkPath::kConcave_Convexity },
504 };
505
506 for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
507 SkPath path;
508 setFromString(&path, gRec[i].fPathStr);
509 SkPath::Convexity c = SkPath::ComputeConvexity(path);
510 REPORTER_ASSERT(reporter, c == gRec[i].fExpectedConvexity);
511 }
512}
513
reed@google.com7e6c4d12012-05-10 14:05:43 +0000514static void test_isLine(skiatest::Reporter* reporter) {
515 SkPath path;
516 SkPoint pts[2];
517 const SkScalar value = SkIntToScalar(5);
518
519 REPORTER_ASSERT(reporter, !path.isLine(NULL));
520
521 // set some non-zero values
522 pts[0].set(value, value);
523 pts[1].set(value, value);
524 REPORTER_ASSERT(reporter, !path.isLine(pts));
525 // check that pts was untouched
526 REPORTER_ASSERT(reporter, pts[0].equals(value, value));
527 REPORTER_ASSERT(reporter, pts[1].equals(value, value));
528
529 const SkScalar moveX = SkIntToScalar(1);
530 const SkScalar moveY = SkIntToScalar(2);
531 SkASSERT(value != moveX && value != moveY);
532
533 path.moveTo(moveX, moveY);
534 REPORTER_ASSERT(reporter, !path.isLine(NULL));
535 REPORTER_ASSERT(reporter, !path.isLine(pts));
536 // check that pts was untouched
537 REPORTER_ASSERT(reporter, pts[0].equals(value, value));
538 REPORTER_ASSERT(reporter, pts[1].equals(value, value));
539
540 const SkScalar lineX = SkIntToScalar(2);
541 const SkScalar lineY = SkIntToScalar(2);
542 SkASSERT(value != lineX && value != lineY);
543
544 path.lineTo(lineX, lineY);
545 REPORTER_ASSERT(reporter, path.isLine(NULL));
546
547 REPORTER_ASSERT(reporter, !pts[0].equals(moveX, moveY));
548 REPORTER_ASSERT(reporter, !pts[1].equals(lineX, lineY));
549 REPORTER_ASSERT(reporter, path.isLine(pts));
550 REPORTER_ASSERT(reporter, pts[0].equals(moveX, moveY));
551 REPORTER_ASSERT(reporter, pts[1].equals(lineX, lineY));
552
553 path.lineTo(0, 0); // too many points/verbs
554 REPORTER_ASSERT(reporter, !path.isLine(NULL));
555 REPORTER_ASSERT(reporter, !path.isLine(pts));
556 REPORTER_ASSERT(reporter, pts[0].equals(moveX, moveY));
557 REPORTER_ASSERT(reporter, pts[1].equals(lineX, lineY));
558}
559
caryclark@google.comf1316942011-07-26 19:54:45 +0000560// Simple isRect test is inline TestPath, below.
561// test_isRect provides more extensive testing.
562static void test_isRect(skiatest::Reporter* reporter) {
563 // passing tests (all moveTo / lineTo...
564 SkPoint r1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
565 SkPoint r2[] = {{1, 0}, {1, 1}, {0, 1}, {0, 0}};
566 SkPoint r3[] = {{1, 1}, {0, 1}, {0, 0}, {1, 0}};
567 SkPoint r4[] = {{0, 1}, {0, 0}, {1, 0}, {1, 1}};
568 SkPoint r5[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}};
569 SkPoint r6[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
570 SkPoint r7[] = {{1, 1}, {1, 0}, {0, 0}, {0, 1}};
571 SkPoint r8[] = {{1, 0}, {0, 0}, {0, 1}, {1, 1}};
572 SkPoint r9[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
573 SkPoint ra[] = {{0, 0}, {0, .5f}, {0, 1}, {.5f, 1}, {1, 1}, {1, .5f},
574 {1, 0}, {.5f, 0}};
575 SkPoint rb[] = {{0, 0}, {.5f, 0}, {1, 0}, {1, .5f}, {1, 1}, {.5f, 1},
576 {0, 1}, {0, .5f}};
577 SkPoint rc[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}};
578 SkPoint rd[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}};
579 SkPoint re[] = {{0, 0}, {1, 0}, {1, 0}, {1, 1}, {0, 1}};
580
581 // failing tests
582 SkPoint f1[] = {{0, 0}, {1, 0}, {1, 1}}; // too few points
583 SkPoint f2[] = {{0, 0}, {1, 1}, {0, 1}, {1, 0}}; // diagonal
584 SkPoint f3[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}, {1, 0}}; // wraps
585 SkPoint f4[] = {{0, 0}, {1, 0}, {0, 0}, {1, 0}, {1, 1}, {0, 1}}; // backs up
586 SkPoint f5[] = {{0, 0}, {1, 0}, {1, 1}, {2, 0}}; // end overshoots
587 SkPoint f6[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 2}}; // end overshoots
588 SkPoint f7[] = {{0, 0}, {1, 0}, {1, 1}, {0, 2}}; // end overshoots
589 SkPoint f8[] = {{0, 0}, {1, 0}, {1, 1}, {1, 0}}; // 'L'
590
591 // failing, no close
592 SkPoint c1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}}; // close doesn't match
593 SkPoint c2[] = {{0, 0}, {1, 0}, {1, 2}, {0, 2}, {0, 1}}; // ditto
594
595 size_t testLen[] = {
596 sizeof(r1), sizeof(r2), sizeof(r3), sizeof(r4), sizeof(r5), sizeof(r6),
597 sizeof(r7), sizeof(r8), sizeof(r9), sizeof(ra), sizeof(rb), sizeof(rc),
598 sizeof(rd), sizeof(re),
599 sizeof(f1), sizeof(f2), sizeof(f3), sizeof(f4), sizeof(f5), sizeof(f6),
600 sizeof(f7), sizeof(f8),
601 sizeof(c1), sizeof(c2)
602 };
603 SkPoint* tests[] = {
604 r1, r2, r3, r4, r5, r6, r7, r8, r9, ra, rb, rc, rd, re,
605 f1, f2, f3, f4, f5, f6, f7, f8,
606 c1, c2
607 };
608 SkPoint* lastPass = re;
609 SkPoint* lastClose = f8;
610 bool fail = false;
611 bool close = true;
612 const size_t testCount = sizeof(tests) / sizeof(tests[0]);
613 size_t index;
614 for (size_t testIndex = 0; testIndex < testCount; ++testIndex) {
615 SkPath path;
616 path.moveTo(tests[testIndex][0].fX, tests[testIndex][0].fY);
617 for (index = 1; index < testLen[testIndex] / sizeof(SkPoint); ++index) {
618 path.lineTo(tests[testIndex][index].fX, tests[testIndex][index].fY);
619 }
620 if (close) {
621 path.close();
622 }
623 REPORTER_ASSERT(reporter, fail ^ path.isRect(0));
624 if (tests[testIndex] == lastPass) {
625 fail = true;
626 }
627 if (tests[testIndex] == lastClose) {
628 close = false;
629 }
630 }
631
632 // fail, close then line
633 SkPath path1;
634 path1.moveTo(r1[0].fX, r1[0].fY);
635 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
636 path1.lineTo(r1[index].fX, r1[index].fY);
637 }
638 path1.close();
639 path1.lineTo(1, 0);
640 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
641
642 // fail, move in the middle
643 path1.reset();
644 path1.moveTo(r1[0].fX, r1[0].fY);
645 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
646 if (index == 2) {
647 path1.moveTo(1, .5f);
648 }
649 path1.lineTo(r1[index].fX, r1[index].fY);
650 }
651 path1.close();
652 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
653
654 // fail, move on the edge
655 path1.reset();
656 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
657 path1.moveTo(r1[index - 1].fX, r1[index - 1].fY);
658 path1.lineTo(r1[index].fX, r1[index].fY);
659 }
660 path1.close();
661 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
662
663 // fail, quad
664 path1.reset();
665 path1.moveTo(r1[0].fX, r1[0].fY);
666 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
667 if (index == 2) {
668 path1.quadTo(1, .5f, 1, .5f);
669 }
670 path1.lineTo(r1[index].fX, r1[index].fY);
671 }
672 path1.close();
673 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
674
675 // fail, cubic
676 path1.reset();
677 path1.moveTo(r1[0].fX, r1[0].fY);
678 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
679 if (index == 2) {
680 path1.cubicTo(1, .5f, 1, .5f, 1, .5f);
681 }
682 path1.lineTo(r1[index].fX, r1[index].fY);
683 }
684 path1.close();
685 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
686}
687
reed@google.com53effc52011-09-21 19:05:12 +0000688static void test_flattening(skiatest::Reporter* reporter) {
689 SkPath p;
690
691 static const SkPoint pts[] = {
692 { 0, 0 },
693 { SkIntToScalar(10), SkIntToScalar(10) },
694 { SkIntToScalar(20), SkIntToScalar(10) }, { SkIntToScalar(20), 0 },
695 { 0, 0 }, { 0, SkIntToScalar(10) }, { SkIntToScalar(1), SkIntToScalar(10) }
696 };
697 p.moveTo(pts[0]);
698 p.lineTo(pts[1]);
699 p.quadTo(pts[2], pts[3]);
700 p.cubicTo(pts[4], pts[5], pts[6]);
701
702 SkWriter32 writer(100);
703 p.flatten(writer);
704 size_t size = writer.size();
705 SkAutoMalloc storage(size);
706 writer.flatten(storage.get());
707 SkReader32 reader(storage.get(), size);
708
709 SkPath p1;
710 REPORTER_ASSERT(reporter, p1 != p);
711 p1.unflatten(reader);
712 REPORTER_ASSERT(reporter, p1 == p);
713}
714
715static void test_transform(skiatest::Reporter* reporter) {
716 SkPath p, p1;
717
718 static const SkPoint pts[] = {
719 { 0, 0 },
720 { SkIntToScalar(10), SkIntToScalar(10) },
721 { SkIntToScalar(20), SkIntToScalar(10) }, { SkIntToScalar(20), 0 },
722 { 0, 0 }, { 0, SkIntToScalar(10) }, { SkIntToScalar(1), SkIntToScalar(10) }
723 };
724 p.moveTo(pts[0]);
725 p.lineTo(pts[1]);
726 p.quadTo(pts[2], pts[3]);
727 p.cubicTo(pts[4], pts[5], pts[6]);
728
729 SkMatrix matrix;
730 matrix.reset();
731 p.transform(matrix, &p1);
732 REPORTER_ASSERT(reporter, p == p1);
733
734 matrix.setScale(SK_Scalar1 * 2, SK_Scalar1 * 3);
735 p.transform(matrix, &p1);
736 SkPoint pts1[7];
737 int count = p1.getPoints(pts1, 7);
738 REPORTER_ASSERT(reporter, 7 == count);
739 for (int i = 0; i < count; ++i) {
740 SkPoint newPt = SkPoint::Make(pts[i].fX * 2, pts[i].fY * 3);
741 REPORTER_ASSERT(reporter, newPt == pts1[i]);
742 }
743}
744
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000745static void test_zero_length_paths(skiatest::Reporter* reporter) {
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000746 SkPath p;
747 SkPoint pt;
748 SkRect bounds;
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000749
750 // Lone moveTo case
751 p.moveTo(SK_Scalar1, SK_Scalar1);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000752 REPORTER_ASSERT(reporter, !p.isEmpty());
753 REPORTER_ASSERT(reporter, 1 == p.countPoints());
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000754 p.getLastPt(&pt);
755 REPORTER_ASSERT(reporter, pt.fX == SK_Scalar1);
756 REPORTER_ASSERT(reporter, pt.fY == SK_Scalar1);
757 bounds.set(0, 0, 0, 0);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000758 REPORTER_ASSERT(reporter, bounds == p.getBounds());
759
760 // MoveTo-MoveTo case
761 p.moveTo(SK_Scalar1*2, SK_Scalar1);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000762 REPORTER_ASSERT(reporter, !p.isEmpty());
763 REPORTER_ASSERT(reporter, 2 == p.countPoints());
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000764 p.getLastPt(&pt);
765 REPORTER_ASSERT(reporter, pt.fX == SK_Scalar1*2);
766 REPORTER_ASSERT(reporter, pt.fY == SK_Scalar1);
767 bounds.set(SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000768 REPORTER_ASSERT(reporter, bounds == p.getBounds());
769
770 // moveTo-close case
771 p.reset();
772 p.moveTo(SK_Scalar1, SK_Scalar1);
773 p.close();
774 bounds.set(0, 0, 0, 0);
775 REPORTER_ASSERT(reporter, !p.isEmpty());
776 REPORTER_ASSERT(reporter, 1 == p.countPoints());
777 REPORTER_ASSERT(reporter, bounds == p.getBounds());
778
779 // moveTo-close-moveTo-close case
780 p.moveTo(SK_Scalar1*2, SK_Scalar1);
781 p.close();
schenney@chromium.org32879492011-12-20 15:33:11 +0000782 bounds.set(SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000783 REPORTER_ASSERT(reporter, !p.isEmpty());
784 REPORTER_ASSERT(reporter, 2 == p.countPoints());
785 REPORTER_ASSERT(reporter, bounds == p.getBounds());
786
787 // moveTo-line case
788 p.reset();
789 p.moveTo(SK_Scalar1, SK_Scalar1);
790 p.lineTo(SK_Scalar1, SK_Scalar1);
791 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
792 REPORTER_ASSERT(reporter, !p.isEmpty());
793 REPORTER_ASSERT(reporter, 2 == p.countPoints());
794 REPORTER_ASSERT(reporter, bounds == p.getBounds());
795
796 // moveTo-lineTo-moveTo-lineTo case
797 p.moveTo(SK_Scalar1*2, SK_Scalar1);
798 p.lineTo(SK_Scalar1*2, SK_Scalar1);
799 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
800 REPORTER_ASSERT(reporter, !p.isEmpty());
801 REPORTER_ASSERT(reporter, 4 == p.countPoints());
802 REPORTER_ASSERT(reporter, bounds == p.getBounds());
803
804 // moveTo-line-close case
805 p.reset();
806 p.moveTo(SK_Scalar1, SK_Scalar1);
807 p.lineTo(SK_Scalar1, SK_Scalar1);
808 p.close();
809 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
810 REPORTER_ASSERT(reporter, !p.isEmpty());
811 REPORTER_ASSERT(reporter, 2 == p.countPoints());
812 REPORTER_ASSERT(reporter, bounds == p.getBounds());
813
814 // moveTo-line-close-moveTo-line-close case
815 p.moveTo(SK_Scalar1*2, SK_Scalar1);
816 p.lineTo(SK_Scalar1*2, SK_Scalar1);
817 p.close();
818 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
819 REPORTER_ASSERT(reporter, !p.isEmpty());
820 REPORTER_ASSERT(reporter, 4 == p.countPoints());
821 REPORTER_ASSERT(reporter, bounds == p.getBounds());
822
823 // moveTo-quadTo case
824 p.reset();
825 p.moveTo(SK_Scalar1, SK_Scalar1);
826 p.quadTo(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
827 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
828 REPORTER_ASSERT(reporter, !p.isEmpty());
829 REPORTER_ASSERT(reporter, 3 == p.countPoints());
830 REPORTER_ASSERT(reporter, bounds == p.getBounds());
831
832 // moveTo-quadTo-close case
833 p.close();
834 REPORTER_ASSERT(reporter, !p.isEmpty());
835 REPORTER_ASSERT(reporter, 3 == p.countPoints());
836 REPORTER_ASSERT(reporter, bounds == p.getBounds());
837
838 // moveTo-quadTo-moveTo-quadTo case
839 p.reset();
840 p.moveTo(SK_Scalar1, SK_Scalar1);
841 p.quadTo(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
842 p.moveTo(SK_Scalar1*2, SK_Scalar1);
843 p.quadTo(SK_Scalar1*2, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
844 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
845 REPORTER_ASSERT(reporter, !p.isEmpty());
846 REPORTER_ASSERT(reporter, 6 == p.countPoints());
847 REPORTER_ASSERT(reporter, bounds == p.getBounds());
848
849 // moveTo-cubicTo case
850 p.reset();
851 p.moveTo(SK_Scalar1, SK_Scalar1);
852 p.cubicTo(SK_Scalar1, SK_Scalar1,
853 SK_Scalar1, SK_Scalar1,
854 SK_Scalar1, SK_Scalar1);
855 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
856 REPORTER_ASSERT(reporter, !p.isEmpty());
857 REPORTER_ASSERT(reporter, 4 == p.countPoints());
858 REPORTER_ASSERT(reporter, bounds == p.getBounds());
859
860 // moveTo-quadTo-close case
861 p.close();
862 REPORTER_ASSERT(reporter, !p.isEmpty());
863 REPORTER_ASSERT(reporter, 4 == p.countPoints());
864 REPORTER_ASSERT(reporter, bounds == p.getBounds());
865
866 // moveTo-quadTo-moveTo-quadTo case
867 p.reset();
868 p.moveTo(SK_Scalar1, SK_Scalar1);
869 p.cubicTo(SK_Scalar1, SK_Scalar1,
870 SK_Scalar1, SK_Scalar1,
871 SK_Scalar1, SK_Scalar1);
872 p.moveTo(SK_Scalar1*2, SK_Scalar1);
873 p.cubicTo(SK_Scalar1*2, SK_Scalar1,
874 SK_Scalar1*2, SK_Scalar1,
875 SK_Scalar1*2, SK_Scalar1);
876 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
877 REPORTER_ASSERT(reporter, !p.isEmpty());
878 REPORTER_ASSERT(reporter, 8 == p.countPoints());
879 REPORTER_ASSERT(reporter, bounds == p.getBounds());
880}
881
882struct SegmentInfo {
883 SkPath fPath;
884 int fPointCount;
885};
886
reed@google.com10296cc2011-09-21 12:29:05 +0000887#define kCurveSegmentMask (SkPath::kQuad_SegmentMask | SkPath::kCubic_SegmentMask)
888
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000889static void test_segment_masks(skiatest::Reporter* reporter) {
890 SkPath p;
891 p.moveTo(0, 0);
892 p.quadTo(100, 100, 200, 200);
893 REPORTER_ASSERT(reporter, SkPath::kQuad_SegmentMask == p.getSegmentMasks());
894 REPORTER_ASSERT(reporter, !p.isEmpty());
895 p.cubicTo(100, 100, 200, 200, 300, 300);
896 REPORTER_ASSERT(reporter, kCurveSegmentMask == p.getSegmentMasks());
897 REPORTER_ASSERT(reporter, !p.isEmpty());
898 p.reset();
899 p.moveTo(0, 0);
900 p.cubicTo(100, 100, 200, 200, 300, 300);
901 REPORTER_ASSERT(reporter, SkPath::kCubic_SegmentMask == p.getSegmentMasks());
902 REPORTER_ASSERT(reporter, !p.isEmpty());
903}
904
905static void test_iter(skiatest::Reporter* reporter) {
906 SkPath p;
907 SkPoint pts[4];
908
909 // Test an iterator with no path
910 SkPath::Iter noPathIter;
911 REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
912 // Test that setting an empty path works
913 noPathIter.setPath(p, false);
914 REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
915 // Test that close path makes no difference for an empty path
916 noPathIter.setPath(p, true);
917 REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
918
919 // Test an iterator with an initial empty path
920 SkPath::Iter iter(p, false);
921 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
922
923 // Test that close path makes no difference
924 SkPath::Iter forceCloseIter(p, true);
925 REPORTER_ASSERT(reporter, forceCloseIter.next(pts) == SkPath::kDone_Verb);
926
927 // Test that a move-only path produces nothing when iterated.
928 p.moveTo(SK_Scalar1, 0);
929 iter.setPath(p, false);
930 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
931
932 // No matter how many moves we add, we should still get nothing back.
933 p.moveTo(SK_Scalar1*2, 0);
934 p.moveTo(SK_Scalar1*3, 0);
935 p.moveTo(SK_Scalar1*4, 0);
936 p.moveTo(SK_Scalar1*5, 0);
937 iter.setPath(p, false);
938 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
939
940 // Nor should force closing
941 forceCloseIter.setPath(p, true);
942 REPORTER_ASSERT(reporter, forceCloseIter.next(pts) == SkPath::kDone_Verb);
943
944 // Initial closes should be ignored
945 p.reset();
946 p.close();
947 iter.setPath(p, false);
948 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
949 // Even if force closed
950 forceCloseIter.setPath(p, true);
951 REPORTER_ASSERT(reporter, forceCloseIter.next(pts) == SkPath::kDone_Verb);
952
953 // Move/close sequences should also be ignored
954 p.reset();
955 p.close();
956 p.moveTo(SK_Scalar1, 0);
957 p.close();
958 p.close();
959 p.moveTo(SK_Scalar1*2, 0);
960 p.close();
961 p.moveTo(SK_Scalar1*3, 0);
962 p.moveTo(SK_Scalar1*4, 0);
963 p.close();
964 iter.setPath(p, false);
965 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
966 // Even if force closed
967 forceCloseIter.setPath(p, true);
968 REPORTER_ASSERT(reporter, forceCloseIter.next(pts) == SkPath::kDone_Verb);
969
970 // The GM degeneratesegments.cpp test is more extensive
971}
972
973static void test_raw_iter(skiatest::Reporter* reporter) {
974 SkPath p;
975 SkPoint pts[4];
976
977 // Test an iterator with no path
978 SkPath::RawIter noPathIter;
979 REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
980 // Test that setting an empty path works
981 noPathIter.setPath(p);
982 REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
983
984 // Test an iterator with an initial empty path
985 SkPath::RawIter iter(p);
986 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
987
988 // Test that a move-only path returns the move.
989 p.moveTo(SK_Scalar1, 0);
990 iter.setPath(p);
991 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
992 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
993 REPORTER_ASSERT(reporter, pts[0].fY == 0);
994 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
995
996 // No matter how many moves we add, we should get them all back
997 p.moveTo(SK_Scalar1*2, SK_Scalar1);
998 p.moveTo(SK_Scalar1*3, SK_Scalar1*2);
999 iter.setPath(p);
1000 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
1001 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
1002 REPORTER_ASSERT(reporter, pts[0].fY == 0);
1003 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
1004 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2);
1005 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1);
1006 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
1007 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*3);
1008 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*2);
1009 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
1010
1011 // Initial close is never ever stored
1012 p.reset();
1013 p.close();
1014 iter.setPath(p);
1015 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
1016
1017 // Move/close sequences
1018 p.reset();
1019 p.close(); // Not stored, no purpose
1020 p.moveTo(SK_Scalar1, 0);
1021 p.close();
1022 p.close(); // Not stored, no purpose
1023 p.moveTo(SK_Scalar1*2, SK_Scalar1);
1024 p.close();
1025 p.moveTo(SK_Scalar1*3, SK_Scalar1*2);
1026 p.moveTo(SK_Scalar1*4, SK_Scalar1*3);
1027 p.close();
1028 iter.setPath(p);
1029 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
1030 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
1031 REPORTER_ASSERT(reporter, pts[0].fY == 0);
1032 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kClose_Verb);
1033 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
1034 REPORTER_ASSERT(reporter, pts[0].fY == 0);
1035 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
1036 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2);
1037 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1);
1038 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kClose_Verb);
1039 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2);
1040 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1);
1041 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
1042 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*3);
1043 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*2);
1044 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
1045 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*4);
1046 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*3);
1047 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kClose_Verb);
1048 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*4);
1049 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*3);
1050 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
1051
1052 // Generate random paths and verify
1053 SkPoint randomPts[25];
1054 for (int i = 0; i < 5; ++i) {
1055 for (int j = 0; j < 5; ++j) {
1056 randomPts[i*5+j].set(SK_Scalar1*i, SK_Scalar1*j);
1057 }
1058 }
1059
1060 // Max of 10 segments, max 3 points per segment
1061 SkRandom rand(9876543);
1062 SkPoint expectedPts[31]; // May have leading moveTo
reed@google.comd335d1d2012-01-12 18:17:11 +00001063 SkPath::Verb expectedVerbs[22]; // May have leading moveTo
schenney@chromium.org6630d8d2012-01-04 21:05:51 +00001064 SkPath::Verb nextVerb;
reed@google.comd335d1d2012-01-12 18:17:11 +00001065
schenney@chromium.org6630d8d2012-01-04 21:05:51 +00001066 for (int i = 0; i < 500; ++i) {
1067 p.reset();
1068 bool lastWasClose = true;
1069 bool haveMoveTo = false;
reed@google.comd335d1d2012-01-12 18:17:11 +00001070 SkPoint lastMoveToPt = { 0, 0 };
schenney@chromium.org6630d8d2012-01-04 21:05:51 +00001071 int numPoints = 0;
1072 int numVerbs = (rand.nextU() >> 16) % 10;
1073 int numIterVerbs = 0;
1074 for (int j = 0; j < numVerbs; ++j) {
1075 do {
1076 nextVerb = static_cast<SkPath::Verb>((rand.nextU() >> 16) % SkPath::kDone_Verb);
1077 } while (lastWasClose && nextVerb == SkPath::kClose_Verb);
schenney@chromium.org6630d8d2012-01-04 21:05:51 +00001078 switch (nextVerb) {
1079 case SkPath::kMove_Verb:
1080 expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
1081 p.moveTo(expectedPts[numPoints]);
reed@google.comd335d1d2012-01-12 18:17:11 +00001082 lastMoveToPt = expectedPts[numPoints];
schenney@chromium.org6630d8d2012-01-04 21:05:51 +00001083 numPoints += 1;
1084 lastWasClose = false;
1085 haveMoveTo = true;
1086 break;
1087 case SkPath::kLine_Verb:
1088 if (!haveMoveTo) {
reed@google.comd335d1d2012-01-12 18:17:11 +00001089 expectedPts[numPoints++] = lastMoveToPt;
schenney@chromium.org6630d8d2012-01-04 21:05:51 +00001090 expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
1091 haveMoveTo = true;
1092 }
1093 expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
1094 p.lineTo(expectedPts[numPoints]);
1095 numPoints += 1;
1096 lastWasClose = false;
1097 break;
1098 case SkPath::kQuad_Verb:
1099 if (!haveMoveTo) {
reed@google.comd335d1d2012-01-12 18:17:11 +00001100 expectedPts[numPoints++] = lastMoveToPt;
schenney@chromium.org6630d8d2012-01-04 21:05:51 +00001101 expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
1102 haveMoveTo = true;
1103 }
1104 expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
1105 expectedPts[numPoints + 1] = randomPts[(rand.nextU() >> 16) % 25];
1106 p.quadTo(expectedPts[numPoints], expectedPts[numPoints + 1]);
1107 numPoints += 2;
1108 lastWasClose = false;
1109 break;
1110 case SkPath::kCubic_Verb:
1111 if (!haveMoveTo) {
reed@google.comd335d1d2012-01-12 18:17:11 +00001112 expectedPts[numPoints++] = lastMoveToPt;
schenney@chromium.org6630d8d2012-01-04 21:05:51 +00001113 expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
1114 haveMoveTo = true;
1115 }
1116 expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
1117 expectedPts[numPoints + 1] = randomPts[(rand.nextU() >> 16) % 25];
1118 expectedPts[numPoints + 2] = randomPts[(rand.nextU() >> 16) % 25];
1119 p.cubicTo(expectedPts[numPoints], expectedPts[numPoints + 1],
1120 expectedPts[numPoints + 2]);
1121 numPoints += 3;
1122 lastWasClose = false;
1123 break;
1124 case SkPath::kClose_Verb:
1125 p.close();
reed@google.comd335d1d2012-01-12 18:17:11 +00001126 haveMoveTo = false;
schenney@chromium.org6630d8d2012-01-04 21:05:51 +00001127 lastWasClose = true;
1128 break;
1129 default:;
1130 }
1131 expectedVerbs[numIterVerbs++] = nextVerb;
1132 }
1133
1134 iter.setPath(p);
1135 numVerbs = numIterVerbs;
1136 numIterVerbs = 0;
1137 int numIterPts = 0;
1138 SkPoint lastMoveTo;
1139 SkPoint lastPt;
1140 lastMoveTo.set(0, 0);
1141 lastPt.set(0, 0);
1142 while ((nextVerb = iter.next(pts)) != SkPath::kDone_Verb) {
1143 REPORTER_ASSERT(reporter, nextVerb == expectedVerbs[numIterVerbs]);
1144 numIterVerbs++;
1145 switch (nextVerb) {
1146 case SkPath::kMove_Verb:
1147 REPORTER_ASSERT(reporter, numIterPts < numPoints);
1148 REPORTER_ASSERT(reporter, pts[0] == expectedPts[numIterPts]);
1149 lastPt = lastMoveTo = pts[0];
1150 numIterPts += 1;
1151 break;
1152 case SkPath::kLine_Verb:
1153 REPORTER_ASSERT(reporter, numIterPts < numPoints + 1);
1154 REPORTER_ASSERT(reporter, pts[0] == lastPt);
1155 REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]);
1156 lastPt = pts[1];
1157 numIterPts += 1;
1158 break;
1159 case SkPath::kQuad_Verb:
1160 REPORTER_ASSERT(reporter, numIterPts < numPoints + 2);
1161 REPORTER_ASSERT(reporter, pts[0] == lastPt);
1162 REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]);
1163 REPORTER_ASSERT(reporter, pts[2] == expectedPts[numIterPts + 1]);
1164 lastPt = pts[2];
1165 numIterPts += 2;
1166 break;
1167 case SkPath::kCubic_Verb:
1168 REPORTER_ASSERT(reporter, numIterPts < numPoints + 3);
1169 REPORTER_ASSERT(reporter, pts[0] == lastPt);
1170 REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]);
1171 REPORTER_ASSERT(reporter, pts[2] == expectedPts[numIterPts + 1]);
1172 REPORTER_ASSERT(reporter, pts[3] == expectedPts[numIterPts + 2]);
1173 lastPt = pts[3];
1174 numIterPts += 3;
1175 break;
1176 case SkPath::kClose_Verb:
1177 REPORTER_ASSERT(reporter, pts[0] == lastMoveTo);
1178 lastPt = lastMoveTo;
1179 break;
1180 default:;
1181 }
1182 }
1183 REPORTER_ASSERT(reporter, numIterPts == numPoints);
1184 REPORTER_ASSERT(reporter, numIterVerbs == numVerbs);
1185 }
1186}
1187
bsalomon@google.com6aa29652012-04-18 13:29:52 +00001188static void check_for_circle(skiatest::Reporter* reporter,
1189 const SkPath& path, bool expected) {
1190 SkRect rect;
1191 REPORTER_ASSERT(reporter, path.isOval(&rect) == expected);
1192 if (expected) {
1193 REPORTER_ASSERT(reporter, rect.height() == rect.width());
1194 }
1195}
1196
1197static void test_circle_skew(skiatest::Reporter* reporter,
1198 const SkPath& path) {
1199 SkPath tmp;
1200
1201 SkMatrix m;
1202 m.setSkew(SkIntToScalar(3), SkIntToScalar(5));
1203 path.transform(m, &tmp);
1204 check_for_circle(reporter, tmp, false);
1205}
1206
1207static void test_circle_translate(skiatest::Reporter* reporter,
1208 const SkPath& path) {
1209 SkPath tmp;
1210
1211 // translate at small offset
1212 SkMatrix m;
1213 m.setTranslate(SkIntToScalar(15), SkIntToScalar(15));
1214 path.transform(m, &tmp);
1215 check_for_circle(reporter, tmp, true);
1216
1217 tmp.reset();
1218 m.reset();
1219
1220 // translate at a relatively big offset
1221 m.setTranslate(SkIntToScalar(1000), SkIntToScalar(1000));
1222 path.transform(m, &tmp);
1223 check_for_circle(reporter, tmp, true);
1224}
1225
1226static void test_circle_rotate(skiatest::Reporter* reporter,
1227 const SkPath& path) {
1228 for (int angle = 0; angle < 360; ++angle) {
1229 SkPath tmp;
1230 SkMatrix m;
1231 m.setRotate(SkIntToScalar(angle));
1232 path.transform(m, &tmp);
1233
1234 // TODO: a rotated circle whose rotated angle is not a mutiple of 90
1235 // degrees is not an oval anymore, this can be improved. we made this
1236 // for the simplicity of our implementation.
1237 if (angle % 90 == 0) {
1238 check_for_circle(reporter, tmp, true);
1239 } else {
1240 check_for_circle(reporter, tmp, false);
1241 }
1242 }
1243}
1244
1245static void test_circle_with_direction(skiatest::Reporter* reporter,
1246 SkPath::Direction dir) {
1247 SkPath path;
1248
1249 // circle at origin
1250 path.addCircle(0, 0, SkIntToScalar(20), dir);
1251 check_for_circle(reporter, path, true);
1252 test_circle_rotate(reporter, path);
1253 test_circle_translate(reporter, path);
1254 test_circle_skew(reporter, path);
1255
1256 // circle at an offset at (10, 10)
1257 path.reset();
1258 path.addCircle(SkIntToScalar(10), SkIntToScalar(10),
1259 SkIntToScalar(20), dir);
1260 check_for_circle(reporter, path, true);
1261 test_circle_rotate(reporter, path);
1262 test_circle_translate(reporter, path);
1263 test_circle_skew(reporter, path);
1264}
1265
1266static void test_circle_with_add_paths(skiatest::Reporter* reporter) {
1267 SkPath path;
1268 SkPath circle;
1269 SkPath rect;
1270 SkPath empty;
1271
1272 circle.addCircle(0, 0, SkIntToScalar(10), SkPath::kCW_Direction);
1273 rect.addRect(SkIntToScalar(5), SkIntToScalar(5),
1274 SkIntToScalar(20), SkIntToScalar(20), SkPath::kCW_Direction);
1275
1276 SkMatrix translate;
1277 translate.setTranslate(SkIntToScalar(12), SkIntToScalar(12));
1278
1279 // For simplicity, all the path concatenation related operations
1280 // would mark it non-circle, though in theory it's still a circle.
1281
1282 // empty + circle (translate)
1283 path = empty;
1284 path.addPath(circle, translate);
1285 check_for_circle(reporter, path, false);
1286
1287 // circle + empty (translate)
1288 path = circle;
1289 path.addPath(empty, translate);
1290 check_for_circle(reporter, path, false);
1291
1292 // test reverseAddPath
1293 path = circle;
1294 path.reverseAddPath(rect);
1295 check_for_circle(reporter, path, false);
1296}
1297
1298static void test_circle(skiatest::Reporter* reporter) {
1299 test_circle_with_direction(reporter, SkPath::kCW_Direction);
1300 test_circle_with_direction(reporter, SkPath::kCCW_Direction);
1301
1302 // multiple addCircle()
1303 SkPath path;
1304 path.addCircle(0, 0, SkIntToScalar(10), SkPath::kCW_Direction);
1305 path.addCircle(0, 0, SkIntToScalar(20), SkPath::kCW_Direction);
1306 check_for_circle(reporter, path, false);
1307
1308 // some extra lineTo() would make isOval() fail
1309 path.reset();
1310 path.addCircle(0, 0, SkIntToScalar(10), SkPath::kCW_Direction);
1311 path.lineTo(0, 0);
1312 check_for_circle(reporter, path, false);
1313
1314 // not back to the original point
1315 path.reset();
1316 path.addCircle(0, 0, SkIntToScalar(10), SkPath::kCW_Direction);
1317 path.setLastPt(SkIntToScalar(5), SkIntToScalar(5));
1318 check_for_circle(reporter, path, false);
1319
1320 test_circle_with_add_paths(reporter);
1321}
1322
1323static void test_oval(skiatest::Reporter* reporter) {
1324 SkRect rect;
1325 SkMatrix m;
1326 SkPath path;
1327
1328 rect = SkRect::MakeWH(SkIntToScalar(30), SkIntToScalar(50));
1329 path.addOval(rect);
1330
1331 REPORTER_ASSERT(reporter, path.isOval(NULL));
1332
1333 m.setRotate(SkIntToScalar(90));
1334 SkPath tmp;
1335 path.transform(m, &tmp);
1336 // an oval rotated 90 degrees is still an oval.
1337 REPORTER_ASSERT(reporter, tmp.isOval(NULL));
1338
1339 m.reset();
1340 m.setRotate(SkIntToScalar(30));
1341 tmp.reset();
1342 path.transform(m, &tmp);
1343 // an oval rotated 30 degrees is not an oval anymore.
1344 REPORTER_ASSERT(reporter, !tmp.isOval(NULL));
1345
1346 // since empty path being transformed.
1347 path.reset();
1348 tmp.reset();
1349 m.reset();
1350 path.transform(m, &tmp);
1351 REPORTER_ASSERT(reporter, !tmp.isOval(NULL));
1352
1353 // empty path is not an oval
1354 tmp.reset();
1355 REPORTER_ASSERT(reporter, !tmp.isOval(NULL));
1356
1357 // only has moveTo()s
1358 tmp.reset();
1359 tmp.moveTo(0, 0);
1360 tmp.moveTo(SkIntToScalar(10), SkIntToScalar(10));
1361 REPORTER_ASSERT(reporter, !tmp.isOval(NULL));
1362
1363 // mimic WebKit's calling convention,
1364 // call moveTo() first and then call addOval()
1365 path.reset();
1366 path.moveTo(0, 0);
1367 path.addOval(rect);
1368 REPORTER_ASSERT(reporter, path.isOval(NULL));
1369
1370 // copy path
1371 path.reset();
1372 tmp.reset();
1373 tmp.addOval(rect);
1374 path = tmp;
1375 REPORTER_ASSERT(reporter, path.isOval(NULL));
1376}
1377
reed@google.com04863fa2011-05-15 04:08:24 +00001378void TestPath(skiatest::Reporter* reporter) {
reed@android.com60bc6d52010-02-11 11:09:39 +00001379 {
1380 SkSize size;
1381 size.fWidth = 3.4f;
1382 size.width();
1383 size = SkSize::Make(3,4);
1384 SkISize isize = SkISize::Make(3,4);
1385 }
1386
1387 SkTSize<SkScalar>::Make(3,4);
1388
reed@android.com3abec1d2009-03-02 05:36:20 +00001389 SkPath p, p2;
1390 SkRect bounds, bounds2;
reed@android.com80e39a72009-04-02 16:59:40 +00001391
reed@android.com3abec1d2009-03-02 05:36:20 +00001392 REPORTER_ASSERT(reporter, p.isEmpty());
schenney@chromium.org4da06ab2011-12-20 15:14:18 +00001393 REPORTER_ASSERT(reporter, 0 == p.countPoints());
reed@google.com10296cc2011-09-21 12:29:05 +00001394 REPORTER_ASSERT(reporter, 0 == p.getSegmentMasks());
reed@google.comb54455e2011-05-16 14:16:04 +00001395 REPORTER_ASSERT(reporter, p.isConvex());
reed@android.com3abec1d2009-03-02 05:36:20 +00001396 REPORTER_ASSERT(reporter, p.getFillType() == SkPath::kWinding_FillType);
1397 REPORTER_ASSERT(reporter, !p.isInverseFillType());
1398 REPORTER_ASSERT(reporter, p == p2);
1399 REPORTER_ASSERT(reporter, !(p != p2));
1400
reed@android.comd252db02009-04-01 18:31:44 +00001401 REPORTER_ASSERT(reporter, p.getBounds().isEmpty());
reed@android.com80e39a72009-04-02 16:59:40 +00001402
reed@android.com3abec1d2009-03-02 05:36:20 +00001403 bounds.set(0, 0, SK_Scalar1, SK_Scalar1);
reed@android.com6b82d1a2009-06-03 02:35:01 +00001404
reed@android.com6b82d1a2009-06-03 02:35:01 +00001405 p.addRoundRect(bounds, SK_Scalar1, SK_Scalar1);
1406 check_convex_bounds(reporter, p, bounds);
reed@google.com10296cc2011-09-21 12:29:05 +00001407 // we have quads or cubics
1408 REPORTER_ASSERT(reporter, p.getSegmentMasks() & kCurveSegmentMask);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +00001409 REPORTER_ASSERT(reporter, !p.isEmpty());
reed@google.com62047cf2011-02-07 19:39:09 +00001410
reed@android.com6b82d1a2009-06-03 02:35:01 +00001411 p.reset();
reed@google.com10296cc2011-09-21 12:29:05 +00001412 REPORTER_ASSERT(reporter, 0 == p.getSegmentMasks());
schenney@chromium.org4da06ab2011-12-20 15:14:18 +00001413 REPORTER_ASSERT(reporter, p.isEmpty());
reed@google.com10296cc2011-09-21 12:29:05 +00001414
reed@android.com6b82d1a2009-06-03 02:35:01 +00001415 p.addOval(bounds);
1416 check_convex_bounds(reporter, p, bounds);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +00001417 REPORTER_ASSERT(reporter, !p.isEmpty());
reed@google.com62047cf2011-02-07 19:39:09 +00001418
reed@android.com6b82d1a2009-06-03 02:35:01 +00001419 p.reset();
reed@android.com3abec1d2009-03-02 05:36:20 +00001420 p.addRect(bounds);
reed@android.com6b82d1a2009-06-03 02:35:01 +00001421 check_convex_bounds(reporter, p, bounds);
reed@google.com10296cc2011-09-21 12:29:05 +00001422 // we have only lines
1423 REPORTER_ASSERT(reporter, SkPath::kLine_SegmentMask == p.getSegmentMasks());
schenney@chromium.org4da06ab2011-12-20 15:14:18 +00001424 REPORTER_ASSERT(reporter, !p.isEmpty());
reed@android.com3abec1d2009-03-02 05:36:20 +00001425
1426 REPORTER_ASSERT(reporter, p != p2);
1427 REPORTER_ASSERT(reporter, !(p == p2));
1428
1429 // does getPoints return the right result
1430 REPORTER_ASSERT(reporter, p.getPoints(NULL, 5) == 4);
1431 SkPoint pts[4];
1432 int count = p.getPoints(pts, 4);
1433 REPORTER_ASSERT(reporter, count == 4);
1434 bounds2.set(pts, 4);
1435 REPORTER_ASSERT(reporter, bounds == bounds2);
reed@android.com80e39a72009-04-02 16:59:40 +00001436
reed@android.com3abec1d2009-03-02 05:36:20 +00001437 bounds.offset(SK_Scalar1*3, SK_Scalar1*4);
1438 p.offset(SK_Scalar1*3, SK_Scalar1*4);
reed@android.comd252db02009-04-01 18:31:44 +00001439 REPORTER_ASSERT(reporter, bounds == p.getBounds());
reed@android.com3abec1d2009-03-02 05:36:20 +00001440
reed@android.com3abec1d2009-03-02 05:36:20 +00001441 REPORTER_ASSERT(reporter, p.isRect(NULL));
caryclark@google.comf1316942011-07-26 19:54:45 +00001442 bounds2.setEmpty();
reed@android.com3abec1d2009-03-02 05:36:20 +00001443 REPORTER_ASSERT(reporter, p.isRect(&bounds2));
1444 REPORTER_ASSERT(reporter, bounds == bounds2);
reed@android.com80e39a72009-04-02 16:59:40 +00001445
reed@android.com3abec1d2009-03-02 05:36:20 +00001446 // now force p to not be a rect
1447 bounds.set(0, 0, SK_Scalar1/2, SK_Scalar1/2);
1448 p.addRect(bounds);
1449 REPORTER_ASSERT(reporter, !p.isRect(NULL));
reed@android.com3abec1d2009-03-02 05:36:20 +00001450
reed@google.com7e6c4d12012-05-10 14:05:43 +00001451 test_isLine(reporter);
1452 test_isRect(reporter);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +00001453 test_zero_length_paths(reporter);
reed@google.comcabaf1d2012-01-11 21:03:05 +00001454 test_direction(reporter);
reed@google.com04863fa2011-05-15 04:08:24 +00001455 test_convexity(reporter);
reed@google.com7c424812011-05-15 04:38:34 +00001456 test_convexity2(reporter);
bsalomon@google.comb3b8dfa2011-07-13 17:44:36 +00001457 test_close(reporter);
schenney@chromium.org6630d8d2012-01-04 21:05:51 +00001458 test_segment_masks(reporter);
reed@google.com53effc52011-09-21 19:05:12 +00001459 test_flattening(reporter);
1460 test_transform(reporter);
reed@google.com3563c9e2011-11-14 19:34:57 +00001461 test_bounds(reporter);
schenney@chromium.org6630d8d2012-01-04 21:05:51 +00001462 test_iter(reporter);
1463 test_raw_iter(reporter);
bsalomon@google.com6aa29652012-04-18 13:29:52 +00001464 test_circle(reporter);
1465 test_oval(reporter);
reed@google.com8b06f1a2012-05-29 12:03:46 +00001466 test_strokerec(reporter);
reed@google.com744faba2012-05-29 19:54:52 +00001467 test_addPoly(reporter);
reed@android.com3abec1d2009-03-02 05:36:20 +00001468}
1469
1470#include "TestClassDef.h"
1471DEFINE_TESTCLASS("Path", PathTestClass, TestPath)