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