blob: 9298d53144296e2078780877e7441f507a410150 [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"
schenney@chromium.org6630d8d2012-01-04 21:05:51 +000013#include "SkRandom.h"
reed@google.com53effc52011-09-21 19:05:12 +000014#include "SkReader32.h"
reed@android.com60bc6d52010-02-11 11:09:39 +000015#include "SkSize.h"
reed@google.com53effc52011-09-21 19:05:12 +000016#include "SkWriter32.h"
reed@android.com3abec1d2009-03-02 05:36:20 +000017
reed@google.com3e71a882012-01-10 18:44:37 +000018static void test_direction(skiatest::Reporter* reporter) {
19 size_t i;
20 SkPath path;
21 REPORTER_ASSERT(reporter, !path.cheapComputeDirection(NULL));
22 REPORTER_ASSERT(reporter, !path.cheapIsDirection(SkPath::kCW_Direction));
23 REPORTER_ASSERT(reporter, !path.cheapIsDirection(SkPath::kCCW_Direction));
24
25 static const char* gDegen[] = {
26 "M 10 10",
27 "M 10 10 M 20 20",
28 "M 10 10 L 20 20",
29 "M 10 10 L 10 10 L 10 10",
30 "M 10 10 Q 10 10 10 10",
31 "M 10 10 C 10 10 10 10 10 10",
32 };
33 for (i = 0; i < SK_ARRAY_COUNT(gDegen); ++i) {
34 path.reset();
35 bool valid = SkParsePath::FromSVGString(gDegen[i], &path);
36 REPORTER_ASSERT(reporter, valid);
37 REPORTER_ASSERT(reporter, !path.cheapComputeDirection(NULL));
38 }
39
40 static const char* gCW[] = {
reed@google.comcabaf1d2012-01-11 21:03:05 +000041 "M 10 10 L 10 10 Q 20 10 20 20",
reed@google.com3e71a882012-01-10 18:44:37 +000042 "M 10 10 C 20 10 20 20 20 20",
43 };
44 for (i = 0; i < SK_ARRAY_COUNT(gCW); ++i) {
45 path.reset();
46 bool valid = SkParsePath::FromSVGString(gCW[i], &path);
47 REPORTER_ASSERT(reporter, valid);
48 REPORTER_ASSERT(reporter, path.cheapIsDirection(SkPath::kCW_Direction));
49 }
50
51 static const char* gCCW[] = {
reed@google.comcabaf1d2012-01-11 21:03:05 +000052 "M 10 10 L 10 10 Q 20 10 20 -20",
reed@google.com3e71a882012-01-10 18:44:37 +000053 "M 10 10 C 20 10 20 -20 20 -20",
54 };
55 for (i = 0; i < SK_ARRAY_COUNT(gCCW); ++i) {
56 path.reset();
57 bool valid = SkParsePath::FromSVGString(gCCW[i], &path);
58 REPORTER_ASSERT(reporter, valid);
59 REPORTER_ASSERT(reporter, path.cheapIsDirection(SkPath::kCCW_Direction));
60 }
61}
62
reed@google.comffdb0182011-11-14 19:29:14 +000063static void add_rect(SkPath* path, const SkRect& r) {
64 path->moveTo(r.fLeft, r.fTop);
65 path->lineTo(r.fRight, r.fTop);
66 path->lineTo(r.fRight, r.fBottom);
67 path->lineTo(r.fLeft, r.fBottom);
68 path->close();
69}
70
71static void test_bounds(skiatest::Reporter* reporter) {
72 static const SkRect rects[] = {
reed@google.com3563c9e2011-11-14 19:34:57 +000073 { SkIntToScalar(10), SkIntToScalar(160), SkIntToScalar(610), SkIntToScalar(160) },
74 { SkIntToScalar(610), SkIntToScalar(160), SkIntToScalar(610), SkIntToScalar(199) },
75 { SkIntToScalar(10), SkIntToScalar(198), SkIntToScalar(610), SkIntToScalar(199) },
76 { SkIntToScalar(10), SkIntToScalar(160), SkIntToScalar(10), SkIntToScalar(199) },
reed@google.comffdb0182011-11-14 19:29:14 +000077 };
78
79 SkPath path0, path1;
80 for (size_t i = 0; i < SK_ARRAY_COUNT(rects); ++i) {
81 path0.addRect(rects[i]);
82 add_rect(&path1, rects[i]);
83 }
84
85 REPORTER_ASSERT(reporter, path0.getBounds() == path1.getBounds());
86}
87
reed@google.com55b5f4b2011-09-07 12:23:41 +000088static void stroke_cubic(const SkPoint pts[4]) {
89 SkPath path;
90 path.moveTo(pts[0]);
91 path.cubicTo(pts[1], pts[2], pts[3]);
92
93 SkPaint paint;
94 paint.setStyle(SkPaint::kStroke_Style);
95 paint.setStrokeWidth(SK_Scalar1 * 2);
96
97 SkPath fill;
98 paint.getFillPath(path, &fill);
99}
100
101// just ensure this can run w/o any SkASSERTS firing in the debug build
102// we used to assert due to differences in how we determine a degenerate vector
103// but that was fixed with the introduction of SkPoint::CanNormalize
104static void stroke_tiny_cubic() {
105 SkPoint p0[] = {
106 { 372.0f, 92.0f },
107 { 372.0f, 92.0f },
108 { 372.0f, 92.0f },
109 { 372.0f, 92.0f },
110 };
111
112 stroke_cubic(p0);
113
114 SkPoint p1[] = {
115 { 372.0f, 92.0f },
116 { 372.0007f, 92.000755f },
117 { 371.99927f, 92.003922f },
118 { 371.99826f, 92.003899f },
119 };
120
121 stroke_cubic(p1);
122}
123
bsalomon@google.comb3b8dfa2011-07-13 17:44:36 +0000124static void check_close(skiatest::Reporter* reporter, const SkPath& path) {
125 for (int i = 0; i < 2; ++i) {
126 SkPath::Iter iter(path, (bool)i);
127 SkPoint mv;
128 SkPoint pts[4];
129 SkPath::Verb v;
130 int nMT = 0;
131 int nCL = 0;
tomhudson@google.com221db3c2011-07-28 21:10:29 +0000132 mv.set(0, 0);
bsalomon@google.comb3b8dfa2011-07-13 17:44:36 +0000133 while (SkPath::kDone_Verb != (v = iter.next(pts))) {
134 switch (v) {
135 case SkPath::kMove_Verb:
136 mv = pts[0];
137 ++nMT;
138 break;
139 case SkPath::kClose_Verb:
140 REPORTER_ASSERT(reporter, mv == pts[0]);
141 ++nCL;
142 break;
143 default:
144 break;
145 }
146 }
147 // if we force a close on the interator we should have a close
148 // for every moveTo
149 REPORTER_ASSERT(reporter, !i || nMT == nCL);
150 }
151}
152
153static void test_close(skiatest::Reporter* reporter) {
154 SkPath closePt;
155 closePt.moveTo(0, 0);
156 closePt.close();
157 check_close(reporter, closePt);
158
159 SkPath openPt;
160 openPt.moveTo(0, 0);
161 check_close(reporter, openPt);
162
163 SkPath empty;
164 check_close(reporter, empty);
165 empty.close();
166 check_close(reporter, empty);
167
168 SkPath rect;
169 rect.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
170 check_close(reporter, rect);
171 rect.close();
172 check_close(reporter, rect);
173
174 SkPath quad;
175 quad.quadTo(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
176 check_close(reporter, quad);
177 quad.close();
178 check_close(reporter, quad);
179
180 SkPath cubic;
181 quad.cubicTo(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1,
182 10*SK_Scalar1, 20 * SK_Scalar1, 20*SK_Scalar1);
183 check_close(reporter, cubic);
184 cubic.close();
185 check_close(reporter, cubic);
186
187 SkPath line;
188 line.moveTo(SK_Scalar1, SK_Scalar1);
189 line.lineTo(10 * SK_Scalar1, 10*SK_Scalar1);
190 check_close(reporter, line);
191 line.close();
192 check_close(reporter, line);
193
194 SkPath rect2;
195 rect2.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
196 rect2.close();
197 rect2.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
198 check_close(reporter, rect2);
199 rect2.close();
200 check_close(reporter, rect2);
201
202 SkPath oval3;
203 oval3.addOval(SkRect::MakeWH(SK_Scalar1*100,SK_Scalar1*100));
204 oval3.close();
205 oval3.addOval(SkRect::MakeWH(SK_Scalar1*200,SK_Scalar1*200));
206 check_close(reporter, oval3);
207 oval3.close();
208 check_close(reporter, oval3);
209
210 SkPath moves;
211 moves.moveTo(SK_Scalar1, SK_Scalar1);
212 moves.moveTo(5 * SK_Scalar1, SK_Scalar1);
213 moves.moveTo(SK_Scalar1, 10 * SK_Scalar1);
214 moves.moveTo(10 *SK_Scalar1, SK_Scalar1);
215 check_close(reporter, moves);
reed@google.com55b5f4b2011-09-07 12:23:41 +0000216
217 stroke_tiny_cubic();
bsalomon@google.comb3b8dfa2011-07-13 17:44:36 +0000218}
219
reed@google.com7c424812011-05-15 04:38:34 +0000220static void check_convexity(skiatest::Reporter* reporter, const SkPath& path,
221 SkPath::Convexity expected) {
222 SkPath::Convexity c = SkPath::ComputeConvexity(path);
223 REPORTER_ASSERT(reporter, c == expected);
224}
225
226static void test_convexity2(skiatest::Reporter* reporter) {
227 SkPath pt;
228 pt.moveTo(0, 0);
229 pt.close();
reed@google.comb54455e2011-05-16 14:16:04 +0000230 check_convexity(reporter, pt, SkPath::kConvex_Convexity);
reed@google.com7c424812011-05-15 04:38:34 +0000231
232 SkPath line;
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000233 line.moveTo(12*SK_Scalar1, 20*SK_Scalar1);
234 line.lineTo(-12*SK_Scalar1, -20*SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000235 line.close();
reed@google.comb54455e2011-05-16 14:16:04 +0000236 check_convexity(reporter, pt, SkPath::kConvex_Convexity);
reed@google.com7c424812011-05-15 04:38:34 +0000237
238 SkPath triLeft;
239 triLeft.moveTo(0, 0);
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000240 triLeft.lineTo(SK_Scalar1, 0);
241 triLeft.lineTo(SK_Scalar1, SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000242 triLeft.close();
243 check_convexity(reporter, triLeft, SkPath::kConvex_Convexity);
244
245 SkPath triRight;
246 triRight.moveTo(0, 0);
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000247 triRight.lineTo(-SK_Scalar1, 0);
248 triRight.lineTo(SK_Scalar1, SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000249 triRight.close();
250 check_convexity(reporter, triRight, SkPath::kConvex_Convexity);
251
252 SkPath square;
253 square.moveTo(0, 0);
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000254 square.lineTo(SK_Scalar1, 0);
255 square.lineTo(SK_Scalar1, SK_Scalar1);
256 square.lineTo(0, SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000257 square.close();
258 check_convexity(reporter, square, SkPath::kConvex_Convexity);
259
260 SkPath redundantSquare;
261 redundantSquare.moveTo(0, 0);
262 redundantSquare.lineTo(0, 0);
263 redundantSquare.lineTo(0, 0);
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000264 redundantSquare.lineTo(SK_Scalar1, 0);
265 redundantSquare.lineTo(SK_Scalar1, 0);
266 redundantSquare.lineTo(SK_Scalar1, 0);
267 redundantSquare.lineTo(SK_Scalar1, SK_Scalar1);
268 redundantSquare.lineTo(SK_Scalar1, SK_Scalar1);
269 redundantSquare.lineTo(SK_Scalar1, SK_Scalar1);
270 redundantSquare.lineTo(0, SK_Scalar1);
271 redundantSquare.lineTo(0, SK_Scalar1);
272 redundantSquare.lineTo(0, SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000273 redundantSquare.close();
274 check_convexity(reporter, redundantSquare, SkPath::kConvex_Convexity);
275
276 SkPath bowTie;
277 bowTie.moveTo(0, 0);
278 bowTie.lineTo(0, 0);
279 bowTie.lineTo(0, 0);
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000280 bowTie.lineTo(SK_Scalar1, SK_Scalar1);
281 bowTie.lineTo(SK_Scalar1, SK_Scalar1);
282 bowTie.lineTo(SK_Scalar1, SK_Scalar1);
283 bowTie.lineTo(SK_Scalar1, 0);
284 bowTie.lineTo(SK_Scalar1, 0);
285 bowTie.lineTo(SK_Scalar1, 0);
286 bowTie.lineTo(0, SK_Scalar1);
287 bowTie.lineTo(0, SK_Scalar1);
288 bowTie.lineTo(0, SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000289 bowTie.close();
290 check_convexity(reporter, bowTie, SkPath::kConcave_Convexity);
291
292 SkPath spiral;
293 spiral.moveTo(0, 0);
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000294 spiral.lineTo(100*SK_Scalar1, 0);
295 spiral.lineTo(100*SK_Scalar1, 100*SK_Scalar1);
296 spiral.lineTo(0, 100*SK_Scalar1);
297 spiral.lineTo(0, 50*SK_Scalar1);
298 spiral.lineTo(50*SK_Scalar1, 50*SK_Scalar1);
299 spiral.lineTo(50*SK_Scalar1, 75*SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000300 spiral.close();
reed@google.com85b6e392011-05-15 20:25:17 +0000301 check_convexity(reporter, spiral, SkPath::kConcave_Convexity);
reed@google.com7c424812011-05-15 04:38:34 +0000302
303 SkPath dent;
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000304 dent.moveTo(0, 0);
305 dent.lineTo(100*SK_Scalar1, 100*SK_Scalar1);
306 dent.lineTo(0, 100*SK_Scalar1);
307 dent.lineTo(-50*SK_Scalar1, 200*SK_Scalar1);
308 dent.lineTo(-200*SK_Scalar1, 100*SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000309 dent.close();
310 check_convexity(reporter, dent, SkPath::kConcave_Convexity);
311}
312
reed@android.com6b82d1a2009-06-03 02:35:01 +0000313static void check_convex_bounds(skiatest::Reporter* reporter, const SkPath& p,
314 const SkRect& bounds) {
315 REPORTER_ASSERT(reporter, p.isConvex());
316 REPORTER_ASSERT(reporter, p.getBounds() == bounds);
reed@google.com62047cf2011-02-07 19:39:09 +0000317
reed@android.com6b82d1a2009-06-03 02:35:01 +0000318 SkPath p2(p);
319 REPORTER_ASSERT(reporter, p2.isConvex());
320 REPORTER_ASSERT(reporter, p2.getBounds() == bounds);
321
322 SkPath other;
323 other.swap(p2);
324 REPORTER_ASSERT(reporter, other.isConvex());
325 REPORTER_ASSERT(reporter, other.getBounds() == bounds);
326}
327
reed@google.com04863fa2011-05-15 04:08:24 +0000328static void setFromString(SkPath* path, const char str[]) {
329 bool first = true;
330 while (str) {
331 SkScalar x, y;
332 str = SkParse::FindScalar(str, &x);
333 if (NULL == str) {
334 break;
335 }
336 str = SkParse::FindScalar(str, &y);
337 SkASSERT(str);
338 if (first) {
339 path->moveTo(x, y);
340 first = false;
341 } else {
342 path->lineTo(x, y);
343 }
344 }
345}
346
347static void test_convexity(skiatest::Reporter* reporter) {
reed@google.com04863fa2011-05-15 04:08:24 +0000348 static const SkPath::Convexity C = SkPath::kConcave_Convexity;
349 static const SkPath::Convexity V = SkPath::kConvex_Convexity;
350
351 SkPath path;
352
reed@google.comb54455e2011-05-16 14:16:04 +0000353 REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
reed@google.come3543972012-01-10 18:59:22 +0000354 path.addCircle(0, 0, SkIntToScalar(10));
reed@google.com04863fa2011-05-15 04:08:24 +0000355 REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
reed@google.come3543972012-01-10 18:59:22 +0000356 path.addCircle(0, 0, SkIntToScalar(10)); // 2nd circle
reed@google.com04863fa2011-05-15 04:08:24 +0000357 REPORTER_ASSERT(reporter, C == SkPath::ComputeConvexity(path));
358 path.reset();
reed@google.come3543972012-01-10 18:59:22 +0000359 path.addRect(0, 0, SkIntToScalar(10), SkIntToScalar(10), SkPath::kCCW_Direction);
reed@google.com04863fa2011-05-15 04:08:24 +0000360 REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
reed@google.com3e71a882012-01-10 18:44:37 +0000361 REPORTER_ASSERT(reporter, path.cheapIsDirection(SkPath::kCCW_Direction));
reed@google.com04863fa2011-05-15 04:08:24 +0000362 path.reset();
reed@google.come3543972012-01-10 18:59:22 +0000363 path.addRect(0, 0, SkIntToScalar(10), SkIntToScalar(10), SkPath::kCW_Direction);
reed@google.com04863fa2011-05-15 04:08:24 +0000364 REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
reed@google.com3e71a882012-01-10 18:44:37 +0000365 REPORTER_ASSERT(reporter, path.cheapIsDirection(SkPath::kCW_Direction));
reed@google.com04863fa2011-05-15 04:08:24 +0000366
367 static const struct {
368 const char* fPathStr;
369 SkPath::Convexity fExpectedConvexity;
370 } gRec[] = {
reed@google.comb54455e2011-05-16 14:16:04 +0000371 { "", SkPath::kConvex_Convexity },
372 { "0 0", SkPath::kConvex_Convexity },
373 { "0 0 10 10", SkPath::kConvex_Convexity },
reed@google.com85b6e392011-05-15 20:25:17 +0000374 { "0 0 10 10 20 20 0 0 10 10", SkPath::kConcave_Convexity },
reed@google.com04863fa2011-05-15 04:08:24 +0000375 { "0 0 10 10 10 20", SkPath::kConvex_Convexity },
376 { "0 0 10 10 10 0", SkPath::kConvex_Convexity },
377 { "0 0 10 10 10 0 0 10", SkPath::kConcave_Convexity },
378 { "0 0 10 0 0 10 -10 -10", SkPath::kConcave_Convexity },
379 };
380
381 for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
382 SkPath path;
383 setFromString(&path, gRec[i].fPathStr);
384 SkPath::Convexity c = SkPath::ComputeConvexity(path);
385 REPORTER_ASSERT(reporter, c == gRec[i].fExpectedConvexity);
386 }
387}
388
caryclark@google.comf1316942011-07-26 19:54:45 +0000389// Simple isRect test is inline TestPath, below.
390// test_isRect provides more extensive testing.
391static void test_isRect(skiatest::Reporter* reporter) {
392 // passing tests (all moveTo / lineTo...
393 SkPoint r1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
394 SkPoint r2[] = {{1, 0}, {1, 1}, {0, 1}, {0, 0}};
395 SkPoint r3[] = {{1, 1}, {0, 1}, {0, 0}, {1, 0}};
396 SkPoint r4[] = {{0, 1}, {0, 0}, {1, 0}, {1, 1}};
397 SkPoint r5[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}};
398 SkPoint r6[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
399 SkPoint r7[] = {{1, 1}, {1, 0}, {0, 0}, {0, 1}};
400 SkPoint r8[] = {{1, 0}, {0, 0}, {0, 1}, {1, 1}};
401 SkPoint r9[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
402 SkPoint ra[] = {{0, 0}, {0, .5f}, {0, 1}, {.5f, 1}, {1, 1}, {1, .5f},
403 {1, 0}, {.5f, 0}};
404 SkPoint rb[] = {{0, 0}, {.5f, 0}, {1, 0}, {1, .5f}, {1, 1}, {.5f, 1},
405 {0, 1}, {0, .5f}};
406 SkPoint rc[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}};
407 SkPoint rd[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}};
408 SkPoint re[] = {{0, 0}, {1, 0}, {1, 0}, {1, 1}, {0, 1}};
409
410 // failing tests
411 SkPoint f1[] = {{0, 0}, {1, 0}, {1, 1}}; // too few points
412 SkPoint f2[] = {{0, 0}, {1, 1}, {0, 1}, {1, 0}}; // diagonal
413 SkPoint f3[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}, {1, 0}}; // wraps
414 SkPoint f4[] = {{0, 0}, {1, 0}, {0, 0}, {1, 0}, {1, 1}, {0, 1}}; // backs up
415 SkPoint f5[] = {{0, 0}, {1, 0}, {1, 1}, {2, 0}}; // end overshoots
416 SkPoint f6[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 2}}; // end overshoots
417 SkPoint f7[] = {{0, 0}, {1, 0}, {1, 1}, {0, 2}}; // end overshoots
418 SkPoint f8[] = {{0, 0}, {1, 0}, {1, 1}, {1, 0}}; // 'L'
419
420 // failing, no close
421 SkPoint c1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}}; // close doesn't match
422 SkPoint c2[] = {{0, 0}, {1, 0}, {1, 2}, {0, 2}, {0, 1}}; // ditto
423
424 size_t testLen[] = {
425 sizeof(r1), sizeof(r2), sizeof(r3), sizeof(r4), sizeof(r5), sizeof(r6),
426 sizeof(r7), sizeof(r8), sizeof(r9), sizeof(ra), sizeof(rb), sizeof(rc),
427 sizeof(rd), sizeof(re),
428 sizeof(f1), sizeof(f2), sizeof(f3), sizeof(f4), sizeof(f5), sizeof(f6),
429 sizeof(f7), sizeof(f8),
430 sizeof(c1), sizeof(c2)
431 };
432 SkPoint* tests[] = {
433 r1, r2, r3, r4, r5, r6, r7, r8, r9, ra, rb, rc, rd, re,
434 f1, f2, f3, f4, f5, f6, f7, f8,
435 c1, c2
436 };
437 SkPoint* lastPass = re;
438 SkPoint* lastClose = f8;
439 bool fail = false;
440 bool close = true;
441 const size_t testCount = sizeof(tests) / sizeof(tests[0]);
442 size_t index;
443 for (size_t testIndex = 0; testIndex < testCount; ++testIndex) {
444 SkPath path;
445 path.moveTo(tests[testIndex][0].fX, tests[testIndex][0].fY);
446 for (index = 1; index < testLen[testIndex] / sizeof(SkPoint); ++index) {
447 path.lineTo(tests[testIndex][index].fX, tests[testIndex][index].fY);
448 }
449 if (close) {
450 path.close();
451 }
452 REPORTER_ASSERT(reporter, fail ^ path.isRect(0));
453 if (tests[testIndex] == lastPass) {
454 fail = true;
455 }
456 if (tests[testIndex] == lastClose) {
457 close = false;
458 }
459 }
460
461 // fail, close then line
462 SkPath path1;
463 path1.moveTo(r1[0].fX, r1[0].fY);
464 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
465 path1.lineTo(r1[index].fX, r1[index].fY);
466 }
467 path1.close();
468 path1.lineTo(1, 0);
469 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
470
471 // fail, move in the middle
472 path1.reset();
473 path1.moveTo(r1[0].fX, r1[0].fY);
474 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
475 if (index == 2) {
476 path1.moveTo(1, .5f);
477 }
478 path1.lineTo(r1[index].fX, r1[index].fY);
479 }
480 path1.close();
481 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
482
483 // fail, move on the edge
484 path1.reset();
485 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
486 path1.moveTo(r1[index - 1].fX, r1[index - 1].fY);
487 path1.lineTo(r1[index].fX, r1[index].fY);
488 }
489 path1.close();
490 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
491
492 // fail, quad
493 path1.reset();
494 path1.moveTo(r1[0].fX, r1[0].fY);
495 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
496 if (index == 2) {
497 path1.quadTo(1, .5f, 1, .5f);
498 }
499 path1.lineTo(r1[index].fX, r1[index].fY);
500 }
501 path1.close();
502 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
503
504 // fail, cubic
505 path1.reset();
506 path1.moveTo(r1[0].fX, r1[0].fY);
507 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
508 if (index == 2) {
509 path1.cubicTo(1, .5f, 1, .5f, 1, .5f);
510 }
511 path1.lineTo(r1[index].fX, r1[index].fY);
512 }
513 path1.close();
514 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
515}
516
reed@google.com53effc52011-09-21 19:05:12 +0000517static void test_flattening(skiatest::Reporter* reporter) {
518 SkPath p;
519
520 static const SkPoint pts[] = {
521 { 0, 0 },
522 { SkIntToScalar(10), SkIntToScalar(10) },
523 { SkIntToScalar(20), SkIntToScalar(10) }, { SkIntToScalar(20), 0 },
524 { 0, 0 }, { 0, SkIntToScalar(10) }, { SkIntToScalar(1), SkIntToScalar(10) }
525 };
526 p.moveTo(pts[0]);
527 p.lineTo(pts[1]);
528 p.quadTo(pts[2], pts[3]);
529 p.cubicTo(pts[4], pts[5], pts[6]);
530
531 SkWriter32 writer(100);
532 p.flatten(writer);
533 size_t size = writer.size();
534 SkAutoMalloc storage(size);
535 writer.flatten(storage.get());
536 SkReader32 reader(storage.get(), size);
537
538 SkPath p1;
539 REPORTER_ASSERT(reporter, p1 != p);
540 p1.unflatten(reader);
541 REPORTER_ASSERT(reporter, p1 == p);
542}
543
544static void test_transform(skiatest::Reporter* reporter) {
545 SkPath p, p1;
546
547 static const SkPoint pts[] = {
548 { 0, 0 },
549 { SkIntToScalar(10), SkIntToScalar(10) },
550 { SkIntToScalar(20), SkIntToScalar(10) }, { SkIntToScalar(20), 0 },
551 { 0, 0 }, { 0, SkIntToScalar(10) }, { SkIntToScalar(1), SkIntToScalar(10) }
552 };
553 p.moveTo(pts[0]);
554 p.lineTo(pts[1]);
555 p.quadTo(pts[2], pts[3]);
556 p.cubicTo(pts[4], pts[5], pts[6]);
557
558 SkMatrix matrix;
559 matrix.reset();
560 p.transform(matrix, &p1);
561 REPORTER_ASSERT(reporter, p == p1);
562
563 matrix.setScale(SK_Scalar1 * 2, SK_Scalar1 * 3);
564 p.transform(matrix, &p1);
565 SkPoint pts1[7];
566 int count = p1.getPoints(pts1, 7);
567 REPORTER_ASSERT(reporter, 7 == count);
568 for (int i = 0; i < count; ++i) {
569 SkPoint newPt = SkPoint::Make(pts[i].fX * 2, pts[i].fY * 3);
570 REPORTER_ASSERT(reporter, newPt == pts1[i]);
571 }
572}
573
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000574static void test_zero_length_paths(skiatest::Reporter* reporter) {
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000575 SkPath p;
576 SkPoint pt;
577 SkRect bounds;
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000578
579 // Lone moveTo case
580 p.moveTo(SK_Scalar1, SK_Scalar1);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000581 REPORTER_ASSERT(reporter, !p.isEmpty());
582 REPORTER_ASSERT(reporter, 1 == p.countPoints());
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000583 p.getLastPt(&pt);
584 REPORTER_ASSERT(reporter, pt.fX == SK_Scalar1);
585 REPORTER_ASSERT(reporter, pt.fY == SK_Scalar1);
586 bounds.set(0, 0, 0, 0);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000587 REPORTER_ASSERT(reporter, bounds == p.getBounds());
588
589 // MoveTo-MoveTo case
590 p.moveTo(SK_Scalar1*2, SK_Scalar1);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000591 REPORTER_ASSERT(reporter, !p.isEmpty());
592 REPORTER_ASSERT(reporter, 2 == p.countPoints());
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000593 p.getLastPt(&pt);
594 REPORTER_ASSERT(reporter, pt.fX == SK_Scalar1*2);
595 REPORTER_ASSERT(reporter, pt.fY == SK_Scalar1);
596 bounds.set(SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000597 REPORTER_ASSERT(reporter, bounds == p.getBounds());
598
599 // moveTo-close case
600 p.reset();
601 p.moveTo(SK_Scalar1, SK_Scalar1);
602 p.close();
603 bounds.set(0, 0, 0, 0);
604 REPORTER_ASSERT(reporter, !p.isEmpty());
605 REPORTER_ASSERT(reporter, 1 == p.countPoints());
606 REPORTER_ASSERT(reporter, bounds == p.getBounds());
607
608 // moveTo-close-moveTo-close case
609 p.moveTo(SK_Scalar1*2, SK_Scalar1);
610 p.close();
schenney@chromium.org32879492011-12-20 15:33:11 +0000611 bounds.set(SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000612 REPORTER_ASSERT(reporter, !p.isEmpty());
613 REPORTER_ASSERT(reporter, 2 == p.countPoints());
614 REPORTER_ASSERT(reporter, bounds == p.getBounds());
615
616 // moveTo-line case
617 p.reset();
618 p.moveTo(SK_Scalar1, SK_Scalar1);
619 p.lineTo(SK_Scalar1, SK_Scalar1);
620 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
621 REPORTER_ASSERT(reporter, !p.isEmpty());
622 REPORTER_ASSERT(reporter, 2 == p.countPoints());
623 REPORTER_ASSERT(reporter, bounds == p.getBounds());
624
625 // moveTo-lineTo-moveTo-lineTo case
626 p.moveTo(SK_Scalar1*2, SK_Scalar1);
627 p.lineTo(SK_Scalar1*2, SK_Scalar1);
628 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
629 REPORTER_ASSERT(reporter, !p.isEmpty());
630 REPORTER_ASSERT(reporter, 4 == p.countPoints());
631 REPORTER_ASSERT(reporter, bounds == p.getBounds());
632
633 // moveTo-line-close case
634 p.reset();
635 p.moveTo(SK_Scalar1, SK_Scalar1);
636 p.lineTo(SK_Scalar1, SK_Scalar1);
637 p.close();
638 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
639 REPORTER_ASSERT(reporter, !p.isEmpty());
640 REPORTER_ASSERT(reporter, 2 == p.countPoints());
641 REPORTER_ASSERT(reporter, bounds == p.getBounds());
642
643 // moveTo-line-close-moveTo-line-close case
644 p.moveTo(SK_Scalar1*2, SK_Scalar1);
645 p.lineTo(SK_Scalar1*2, SK_Scalar1);
646 p.close();
647 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
648 REPORTER_ASSERT(reporter, !p.isEmpty());
649 REPORTER_ASSERT(reporter, 4 == p.countPoints());
650 REPORTER_ASSERT(reporter, bounds == p.getBounds());
651
652 // moveTo-quadTo case
653 p.reset();
654 p.moveTo(SK_Scalar1, SK_Scalar1);
655 p.quadTo(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
656 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
657 REPORTER_ASSERT(reporter, !p.isEmpty());
658 REPORTER_ASSERT(reporter, 3 == p.countPoints());
659 REPORTER_ASSERT(reporter, bounds == p.getBounds());
660
661 // moveTo-quadTo-close case
662 p.close();
663 REPORTER_ASSERT(reporter, !p.isEmpty());
664 REPORTER_ASSERT(reporter, 3 == p.countPoints());
665 REPORTER_ASSERT(reporter, bounds == p.getBounds());
666
667 // moveTo-quadTo-moveTo-quadTo case
668 p.reset();
669 p.moveTo(SK_Scalar1, SK_Scalar1);
670 p.quadTo(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
671 p.moveTo(SK_Scalar1*2, SK_Scalar1);
672 p.quadTo(SK_Scalar1*2, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
673 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
674 REPORTER_ASSERT(reporter, !p.isEmpty());
675 REPORTER_ASSERT(reporter, 6 == p.countPoints());
676 REPORTER_ASSERT(reporter, bounds == p.getBounds());
677
678 // moveTo-cubicTo case
679 p.reset();
680 p.moveTo(SK_Scalar1, SK_Scalar1);
681 p.cubicTo(SK_Scalar1, SK_Scalar1,
682 SK_Scalar1, SK_Scalar1,
683 SK_Scalar1, SK_Scalar1);
684 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
685 REPORTER_ASSERT(reporter, !p.isEmpty());
686 REPORTER_ASSERT(reporter, 4 == p.countPoints());
687 REPORTER_ASSERT(reporter, bounds == p.getBounds());
688
689 // moveTo-quadTo-close case
690 p.close();
691 REPORTER_ASSERT(reporter, !p.isEmpty());
692 REPORTER_ASSERT(reporter, 4 == p.countPoints());
693 REPORTER_ASSERT(reporter, bounds == p.getBounds());
694
695 // moveTo-quadTo-moveTo-quadTo case
696 p.reset();
697 p.moveTo(SK_Scalar1, SK_Scalar1);
698 p.cubicTo(SK_Scalar1, SK_Scalar1,
699 SK_Scalar1, SK_Scalar1,
700 SK_Scalar1, SK_Scalar1);
701 p.moveTo(SK_Scalar1*2, SK_Scalar1);
702 p.cubicTo(SK_Scalar1*2, SK_Scalar1,
703 SK_Scalar1*2, SK_Scalar1,
704 SK_Scalar1*2, SK_Scalar1);
705 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
706 REPORTER_ASSERT(reporter, !p.isEmpty());
707 REPORTER_ASSERT(reporter, 8 == p.countPoints());
708 REPORTER_ASSERT(reporter, bounds == p.getBounds());
709}
710
711struct SegmentInfo {
712 SkPath fPath;
713 int fPointCount;
714};
715
reed@google.com10296cc2011-09-21 12:29:05 +0000716#define kCurveSegmentMask (SkPath::kQuad_SegmentMask | SkPath::kCubic_SegmentMask)
717
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000718static void test_segment_masks(skiatest::Reporter* reporter) {
719 SkPath p;
720 p.moveTo(0, 0);
721 p.quadTo(100, 100, 200, 200);
722 REPORTER_ASSERT(reporter, SkPath::kQuad_SegmentMask == p.getSegmentMasks());
723 REPORTER_ASSERT(reporter, !p.isEmpty());
724 p.cubicTo(100, 100, 200, 200, 300, 300);
725 REPORTER_ASSERT(reporter, kCurveSegmentMask == p.getSegmentMasks());
726 REPORTER_ASSERT(reporter, !p.isEmpty());
727 p.reset();
728 p.moveTo(0, 0);
729 p.cubicTo(100, 100, 200, 200, 300, 300);
730 REPORTER_ASSERT(reporter, SkPath::kCubic_SegmentMask == p.getSegmentMasks());
731 REPORTER_ASSERT(reporter, !p.isEmpty());
732}
733
734static void test_iter(skiatest::Reporter* reporter) {
735 SkPath p;
736 SkPoint pts[4];
737
738 // Test an iterator with no path
739 SkPath::Iter noPathIter;
740 REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
741 // Test that setting an empty path works
742 noPathIter.setPath(p, false);
743 REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
744 // Test that close path makes no difference for an empty path
745 noPathIter.setPath(p, true);
746 REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
747
748 // Test an iterator with an initial empty path
749 SkPath::Iter iter(p, false);
750 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
751
752 // Test that close path makes no difference
753 SkPath::Iter forceCloseIter(p, true);
754 REPORTER_ASSERT(reporter, forceCloseIter.next(pts) == SkPath::kDone_Verb);
755
756 // Test that a move-only path produces nothing when iterated.
757 p.moveTo(SK_Scalar1, 0);
758 iter.setPath(p, false);
759 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
760
761 // No matter how many moves we add, we should still get nothing back.
762 p.moveTo(SK_Scalar1*2, 0);
763 p.moveTo(SK_Scalar1*3, 0);
764 p.moveTo(SK_Scalar1*4, 0);
765 p.moveTo(SK_Scalar1*5, 0);
766 iter.setPath(p, false);
767 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
768
769 // Nor should force closing
770 forceCloseIter.setPath(p, true);
771 REPORTER_ASSERT(reporter, forceCloseIter.next(pts) == SkPath::kDone_Verb);
772
773 // Initial closes should be ignored
774 p.reset();
775 p.close();
776 iter.setPath(p, false);
777 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
778 // Even if force closed
779 forceCloseIter.setPath(p, true);
780 REPORTER_ASSERT(reporter, forceCloseIter.next(pts) == SkPath::kDone_Verb);
781
782 // Move/close sequences should also be ignored
783 p.reset();
784 p.close();
785 p.moveTo(SK_Scalar1, 0);
786 p.close();
787 p.close();
788 p.moveTo(SK_Scalar1*2, 0);
789 p.close();
790 p.moveTo(SK_Scalar1*3, 0);
791 p.moveTo(SK_Scalar1*4, 0);
792 p.close();
793 iter.setPath(p, false);
794 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
795 // Even if force closed
796 forceCloseIter.setPath(p, true);
797 REPORTER_ASSERT(reporter, forceCloseIter.next(pts) == SkPath::kDone_Verb);
798
799 // The GM degeneratesegments.cpp test is more extensive
800}
801
802static void test_raw_iter(skiatest::Reporter* reporter) {
803 SkPath p;
804 SkPoint pts[4];
805
806 // Test an iterator with no path
807 SkPath::RawIter noPathIter;
808 REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
809 // Test that setting an empty path works
810 noPathIter.setPath(p);
811 REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
812
813 // Test an iterator with an initial empty path
814 SkPath::RawIter iter(p);
815 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
816
817 // Test that a move-only path returns the move.
818 p.moveTo(SK_Scalar1, 0);
819 iter.setPath(p);
820 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
821 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
822 REPORTER_ASSERT(reporter, pts[0].fY == 0);
823 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
824
825 // No matter how many moves we add, we should get them all back
826 p.moveTo(SK_Scalar1*2, SK_Scalar1);
827 p.moveTo(SK_Scalar1*3, SK_Scalar1*2);
828 iter.setPath(p);
829 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
830 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
831 REPORTER_ASSERT(reporter, pts[0].fY == 0);
832 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
833 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2);
834 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1);
835 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
836 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*3);
837 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*2);
838 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
839
840 // Initial close is never ever stored
841 p.reset();
842 p.close();
843 iter.setPath(p);
844 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
845
846 // Move/close sequences
847 p.reset();
848 p.close(); // Not stored, no purpose
849 p.moveTo(SK_Scalar1, 0);
850 p.close();
851 p.close(); // Not stored, no purpose
852 p.moveTo(SK_Scalar1*2, SK_Scalar1);
853 p.close();
854 p.moveTo(SK_Scalar1*3, SK_Scalar1*2);
855 p.moveTo(SK_Scalar1*4, SK_Scalar1*3);
856 p.close();
857 iter.setPath(p);
858 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
859 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
860 REPORTER_ASSERT(reporter, pts[0].fY == 0);
861 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kClose_Verb);
862 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
863 REPORTER_ASSERT(reporter, pts[0].fY == 0);
864 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
865 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2);
866 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1);
867 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kClose_Verb);
868 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2);
869 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1);
870 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
871 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*3);
872 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*2);
873 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
874 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*4);
875 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*3);
876 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kClose_Verb);
877 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*4);
878 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*3);
879 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
880
881 // Generate random paths and verify
882 SkPoint randomPts[25];
883 for (int i = 0; i < 5; ++i) {
884 for (int j = 0; j < 5; ++j) {
885 randomPts[i*5+j].set(SK_Scalar1*i, SK_Scalar1*j);
886 }
887 }
888
889 // Max of 10 segments, max 3 points per segment
890 SkRandom rand(9876543);
891 SkPoint expectedPts[31]; // May have leading moveTo
reed@google.comd335d1d2012-01-12 18:17:11 +0000892 SkPath::Verb expectedVerbs[22]; // May have leading moveTo
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000893 SkPath::Verb nextVerb;
reed@google.comd335d1d2012-01-12 18:17:11 +0000894
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000895 for (int i = 0; i < 500; ++i) {
896 p.reset();
897 bool lastWasClose = true;
898 bool haveMoveTo = false;
reed@google.comd335d1d2012-01-12 18:17:11 +0000899 SkPoint lastMoveToPt = { 0, 0 };
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000900 int numPoints = 0;
901 int numVerbs = (rand.nextU() >> 16) % 10;
902 int numIterVerbs = 0;
903 for (int j = 0; j < numVerbs; ++j) {
904 do {
905 nextVerb = static_cast<SkPath::Verb>((rand.nextU() >> 16) % SkPath::kDone_Verb);
906 } while (lastWasClose && nextVerb == SkPath::kClose_Verb);
907 int numRequiredPts;
908 switch (nextVerb) {
909 case SkPath::kMove_Verb:
910 expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
911 p.moveTo(expectedPts[numPoints]);
reed@google.comd335d1d2012-01-12 18:17:11 +0000912 lastMoveToPt = expectedPts[numPoints];
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000913 numPoints += 1;
914 lastWasClose = false;
915 haveMoveTo = true;
916 break;
917 case SkPath::kLine_Verb:
918 if (!haveMoveTo) {
reed@google.comd335d1d2012-01-12 18:17:11 +0000919 expectedPts[numPoints++] = lastMoveToPt;
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000920 expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
921 haveMoveTo = true;
922 }
923 expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
924 p.lineTo(expectedPts[numPoints]);
925 numPoints += 1;
926 lastWasClose = false;
927 break;
928 case SkPath::kQuad_Verb:
929 if (!haveMoveTo) {
reed@google.comd335d1d2012-01-12 18:17:11 +0000930 expectedPts[numPoints++] = lastMoveToPt;
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000931 expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
932 haveMoveTo = true;
933 }
934 expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
935 expectedPts[numPoints + 1] = randomPts[(rand.nextU() >> 16) % 25];
936 p.quadTo(expectedPts[numPoints], expectedPts[numPoints + 1]);
937 numPoints += 2;
938 lastWasClose = false;
939 break;
940 case SkPath::kCubic_Verb:
941 if (!haveMoveTo) {
reed@google.comd335d1d2012-01-12 18:17:11 +0000942 expectedPts[numPoints++] = lastMoveToPt;
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000943 expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
944 haveMoveTo = true;
945 }
946 expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
947 expectedPts[numPoints + 1] = randomPts[(rand.nextU() >> 16) % 25];
948 expectedPts[numPoints + 2] = randomPts[(rand.nextU() >> 16) % 25];
949 p.cubicTo(expectedPts[numPoints], expectedPts[numPoints + 1],
950 expectedPts[numPoints + 2]);
951 numPoints += 3;
952 lastWasClose = false;
953 break;
954 case SkPath::kClose_Verb:
955 p.close();
reed@google.comd335d1d2012-01-12 18:17:11 +0000956 haveMoveTo = false;
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000957 lastWasClose = true;
958 break;
959 default:;
960 }
961 expectedVerbs[numIterVerbs++] = nextVerb;
962 }
963
964 iter.setPath(p);
965 numVerbs = numIterVerbs;
966 numIterVerbs = 0;
967 int numIterPts = 0;
968 SkPoint lastMoveTo;
969 SkPoint lastPt;
970 lastMoveTo.set(0, 0);
971 lastPt.set(0, 0);
972 while ((nextVerb = iter.next(pts)) != SkPath::kDone_Verb) {
973 REPORTER_ASSERT(reporter, nextVerb == expectedVerbs[numIterVerbs]);
974 numIterVerbs++;
975 switch (nextVerb) {
976 case SkPath::kMove_Verb:
977 REPORTER_ASSERT(reporter, numIterPts < numPoints);
978 REPORTER_ASSERT(reporter, pts[0] == expectedPts[numIterPts]);
979 lastPt = lastMoveTo = pts[0];
980 numIterPts += 1;
981 break;
982 case SkPath::kLine_Verb:
983 REPORTER_ASSERT(reporter, numIterPts < numPoints + 1);
984 REPORTER_ASSERT(reporter, pts[0] == lastPt);
985 REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]);
986 lastPt = pts[1];
987 numIterPts += 1;
988 break;
989 case SkPath::kQuad_Verb:
990 REPORTER_ASSERT(reporter, numIterPts < numPoints + 2);
991 REPORTER_ASSERT(reporter, pts[0] == lastPt);
992 REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]);
993 REPORTER_ASSERT(reporter, pts[2] == expectedPts[numIterPts + 1]);
994 lastPt = pts[2];
995 numIterPts += 2;
996 break;
997 case SkPath::kCubic_Verb:
998 REPORTER_ASSERT(reporter, numIterPts < numPoints + 3);
999 REPORTER_ASSERT(reporter, pts[0] == lastPt);
1000 REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]);
1001 REPORTER_ASSERT(reporter, pts[2] == expectedPts[numIterPts + 1]);
1002 REPORTER_ASSERT(reporter, pts[3] == expectedPts[numIterPts + 2]);
1003 lastPt = pts[3];
1004 numIterPts += 3;
1005 break;
1006 case SkPath::kClose_Verb:
1007 REPORTER_ASSERT(reporter, pts[0] == lastMoveTo);
1008 lastPt = lastMoveTo;
1009 break;
1010 default:;
1011 }
1012 }
1013 REPORTER_ASSERT(reporter, numIterPts == numPoints);
1014 REPORTER_ASSERT(reporter, numIterVerbs == numVerbs);
1015 }
1016}
1017
reed@google.com04863fa2011-05-15 04:08:24 +00001018void TestPath(skiatest::Reporter* reporter);
1019void TestPath(skiatest::Reporter* reporter) {
reed@android.com60bc6d52010-02-11 11:09:39 +00001020 {
1021 SkSize size;
1022 size.fWidth = 3.4f;
1023 size.width();
1024 size = SkSize::Make(3,4);
1025 SkISize isize = SkISize::Make(3,4);
1026 }
1027
1028 SkTSize<SkScalar>::Make(3,4);
1029
reed@android.com3abec1d2009-03-02 05:36:20 +00001030 SkPath p, p2;
1031 SkRect bounds, bounds2;
reed@android.com80e39a72009-04-02 16:59:40 +00001032
reed@android.com3abec1d2009-03-02 05:36:20 +00001033 REPORTER_ASSERT(reporter, p.isEmpty());
schenney@chromium.org4da06ab2011-12-20 15:14:18 +00001034 REPORTER_ASSERT(reporter, 0 == p.countPoints());
reed@google.com10296cc2011-09-21 12:29:05 +00001035 REPORTER_ASSERT(reporter, 0 == p.getSegmentMasks());
reed@google.comb54455e2011-05-16 14:16:04 +00001036 REPORTER_ASSERT(reporter, p.isConvex());
reed@android.com3abec1d2009-03-02 05:36:20 +00001037 REPORTER_ASSERT(reporter, p.getFillType() == SkPath::kWinding_FillType);
1038 REPORTER_ASSERT(reporter, !p.isInverseFillType());
1039 REPORTER_ASSERT(reporter, p == p2);
1040 REPORTER_ASSERT(reporter, !(p != p2));
1041
reed@android.comd252db02009-04-01 18:31:44 +00001042 REPORTER_ASSERT(reporter, p.getBounds().isEmpty());
reed@android.com80e39a72009-04-02 16:59:40 +00001043
reed@android.com3abec1d2009-03-02 05:36:20 +00001044 bounds.set(0, 0, SK_Scalar1, SK_Scalar1);
reed@android.com6b82d1a2009-06-03 02:35:01 +00001045
reed@android.com6b82d1a2009-06-03 02:35:01 +00001046 p.addRoundRect(bounds, SK_Scalar1, SK_Scalar1);
1047 check_convex_bounds(reporter, p, bounds);
reed@google.com10296cc2011-09-21 12:29:05 +00001048 // we have quads or cubics
1049 REPORTER_ASSERT(reporter, p.getSegmentMasks() & kCurveSegmentMask);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +00001050 REPORTER_ASSERT(reporter, !p.isEmpty());
reed@google.com62047cf2011-02-07 19:39:09 +00001051
reed@android.com6b82d1a2009-06-03 02:35:01 +00001052 p.reset();
reed@google.com10296cc2011-09-21 12:29:05 +00001053 REPORTER_ASSERT(reporter, 0 == p.getSegmentMasks());
schenney@chromium.org4da06ab2011-12-20 15:14:18 +00001054 REPORTER_ASSERT(reporter, p.isEmpty());
reed@google.com10296cc2011-09-21 12:29:05 +00001055
reed@android.com6b82d1a2009-06-03 02:35:01 +00001056 p.addOval(bounds);
1057 check_convex_bounds(reporter, p, bounds);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +00001058 REPORTER_ASSERT(reporter, !p.isEmpty());
reed@google.com62047cf2011-02-07 19:39:09 +00001059
reed@android.com6b82d1a2009-06-03 02:35:01 +00001060 p.reset();
reed@android.com3abec1d2009-03-02 05:36:20 +00001061 p.addRect(bounds);
reed@android.com6b82d1a2009-06-03 02:35:01 +00001062 check_convex_bounds(reporter, p, bounds);
reed@google.com10296cc2011-09-21 12:29:05 +00001063 // we have only lines
1064 REPORTER_ASSERT(reporter, SkPath::kLine_SegmentMask == p.getSegmentMasks());
schenney@chromium.org4da06ab2011-12-20 15:14:18 +00001065 REPORTER_ASSERT(reporter, !p.isEmpty());
reed@android.com3abec1d2009-03-02 05:36:20 +00001066
1067 REPORTER_ASSERT(reporter, p != p2);
1068 REPORTER_ASSERT(reporter, !(p == p2));
1069
1070 // does getPoints return the right result
1071 REPORTER_ASSERT(reporter, p.getPoints(NULL, 5) == 4);
1072 SkPoint pts[4];
1073 int count = p.getPoints(pts, 4);
1074 REPORTER_ASSERT(reporter, count == 4);
1075 bounds2.set(pts, 4);
1076 REPORTER_ASSERT(reporter, bounds == bounds2);
reed@android.com80e39a72009-04-02 16:59:40 +00001077
reed@android.com3abec1d2009-03-02 05:36:20 +00001078 bounds.offset(SK_Scalar1*3, SK_Scalar1*4);
1079 p.offset(SK_Scalar1*3, SK_Scalar1*4);
reed@android.comd252db02009-04-01 18:31:44 +00001080 REPORTER_ASSERT(reporter, bounds == p.getBounds());
reed@android.com3abec1d2009-03-02 05:36:20 +00001081
reed@android.com3abec1d2009-03-02 05:36:20 +00001082 REPORTER_ASSERT(reporter, p.isRect(NULL));
caryclark@google.comf1316942011-07-26 19:54:45 +00001083 bounds2.setEmpty();
reed@android.com3abec1d2009-03-02 05:36:20 +00001084 REPORTER_ASSERT(reporter, p.isRect(&bounds2));
1085 REPORTER_ASSERT(reporter, bounds == bounds2);
reed@android.com80e39a72009-04-02 16:59:40 +00001086
reed@android.com3abec1d2009-03-02 05:36:20 +00001087 // now force p to not be a rect
1088 bounds.set(0, 0, SK_Scalar1/2, SK_Scalar1/2);
1089 p.addRect(bounds);
1090 REPORTER_ASSERT(reporter, !p.isRect(NULL));
caryclark@google.comf1316942011-07-26 19:54:45 +00001091 test_isRect(reporter);
reed@android.com3abec1d2009-03-02 05:36:20 +00001092
schenney@chromium.org4da06ab2011-12-20 15:14:18 +00001093 test_zero_length_paths(reporter);
reed@google.comcabaf1d2012-01-11 21:03:05 +00001094 test_direction(reporter);
reed@google.com04863fa2011-05-15 04:08:24 +00001095 test_convexity(reporter);
reed@google.com7c424812011-05-15 04:38:34 +00001096 test_convexity2(reporter);
bsalomon@google.comb3b8dfa2011-07-13 17:44:36 +00001097 test_close(reporter);
schenney@chromium.org6630d8d2012-01-04 21:05:51 +00001098 test_segment_masks(reporter);
reed@google.com53effc52011-09-21 19:05:12 +00001099 test_flattening(reporter);
1100 test_transform(reporter);
reed@google.com3563c9e2011-11-14 19:34:57 +00001101 test_bounds(reporter);
schenney@chromium.org6630d8d2012-01-04 21:05:51 +00001102 test_iter(reporter);
1103 test_raw_iter(reporter);
reed@android.com3abec1d2009-03-02 05:36:20 +00001104}
1105
1106#include "TestClassDef.h"
1107DEFINE_TESTCLASS("Path", PathTestClass, TestPath)