blob: 270fa68d220b0043510ab03af37b6c570b278e66 [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"
schenney@chromium.org6630d8d2012-01-04 21:05:51 +000012#include "SkRandom.h"
reed@google.com53effc52011-09-21 19:05:12 +000013#include "SkReader32.h"
reed@android.com60bc6d52010-02-11 11:09:39 +000014#include "SkSize.h"
reed@google.com53effc52011-09-21 19:05:12 +000015#include "SkWriter32.h"
reed@android.com3abec1d2009-03-02 05:36:20 +000016
reed@google.comffdb0182011-11-14 19:29:14 +000017static void add_rect(SkPath* path, const SkRect& r) {
18 path->moveTo(r.fLeft, r.fTop);
19 path->lineTo(r.fRight, r.fTop);
20 path->lineTo(r.fRight, r.fBottom);
21 path->lineTo(r.fLeft, r.fBottom);
22 path->close();
23}
24
25static void test_bounds(skiatest::Reporter* reporter) {
26 static const SkRect rects[] = {
reed@google.com3563c9e2011-11-14 19:34:57 +000027 { SkIntToScalar(10), SkIntToScalar(160), SkIntToScalar(610), SkIntToScalar(160) },
28 { SkIntToScalar(610), SkIntToScalar(160), SkIntToScalar(610), SkIntToScalar(199) },
29 { SkIntToScalar(10), SkIntToScalar(198), SkIntToScalar(610), SkIntToScalar(199) },
30 { SkIntToScalar(10), SkIntToScalar(160), SkIntToScalar(10), SkIntToScalar(199) },
reed@google.comffdb0182011-11-14 19:29:14 +000031 };
32
33 SkPath path0, path1;
34 for (size_t i = 0; i < SK_ARRAY_COUNT(rects); ++i) {
35 path0.addRect(rects[i]);
36 add_rect(&path1, rects[i]);
37 }
38
39 REPORTER_ASSERT(reporter, path0.getBounds() == path1.getBounds());
40}
41
reed@google.com55b5f4b2011-09-07 12:23:41 +000042static void stroke_cubic(const SkPoint pts[4]) {
43 SkPath path;
44 path.moveTo(pts[0]);
45 path.cubicTo(pts[1], pts[2], pts[3]);
46
47 SkPaint paint;
48 paint.setStyle(SkPaint::kStroke_Style);
49 paint.setStrokeWidth(SK_Scalar1 * 2);
50
51 SkPath fill;
52 paint.getFillPath(path, &fill);
53}
54
55// just ensure this can run w/o any SkASSERTS firing in the debug build
56// we used to assert due to differences in how we determine a degenerate vector
57// but that was fixed with the introduction of SkPoint::CanNormalize
58static void stroke_tiny_cubic() {
59 SkPoint p0[] = {
60 { 372.0f, 92.0f },
61 { 372.0f, 92.0f },
62 { 372.0f, 92.0f },
63 { 372.0f, 92.0f },
64 };
65
66 stroke_cubic(p0);
67
68 SkPoint p1[] = {
69 { 372.0f, 92.0f },
70 { 372.0007f, 92.000755f },
71 { 371.99927f, 92.003922f },
72 { 371.99826f, 92.003899f },
73 };
74
75 stroke_cubic(p1);
76}
77
bsalomon@google.comb3b8dfa2011-07-13 17:44:36 +000078static void check_close(skiatest::Reporter* reporter, const SkPath& path) {
79 for (int i = 0; i < 2; ++i) {
80 SkPath::Iter iter(path, (bool)i);
81 SkPoint mv;
82 SkPoint pts[4];
83 SkPath::Verb v;
84 int nMT = 0;
85 int nCL = 0;
tomhudson@google.com221db3c2011-07-28 21:10:29 +000086 mv.set(0, 0);
bsalomon@google.comb3b8dfa2011-07-13 17:44:36 +000087 while (SkPath::kDone_Verb != (v = iter.next(pts))) {
88 switch (v) {
89 case SkPath::kMove_Verb:
90 mv = pts[0];
91 ++nMT;
92 break;
93 case SkPath::kClose_Verb:
94 REPORTER_ASSERT(reporter, mv == pts[0]);
95 ++nCL;
96 break;
97 default:
98 break;
99 }
100 }
101 // if we force a close on the interator we should have a close
102 // for every moveTo
103 REPORTER_ASSERT(reporter, !i || nMT == nCL);
104 }
105}
106
107static void test_close(skiatest::Reporter* reporter) {
108 SkPath closePt;
109 closePt.moveTo(0, 0);
110 closePt.close();
111 check_close(reporter, closePt);
112
113 SkPath openPt;
114 openPt.moveTo(0, 0);
115 check_close(reporter, openPt);
116
117 SkPath empty;
118 check_close(reporter, empty);
119 empty.close();
120 check_close(reporter, empty);
121
122 SkPath rect;
123 rect.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
124 check_close(reporter, rect);
125 rect.close();
126 check_close(reporter, rect);
127
128 SkPath quad;
129 quad.quadTo(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
130 check_close(reporter, quad);
131 quad.close();
132 check_close(reporter, quad);
133
134 SkPath cubic;
135 quad.cubicTo(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1,
136 10*SK_Scalar1, 20 * SK_Scalar1, 20*SK_Scalar1);
137 check_close(reporter, cubic);
138 cubic.close();
139 check_close(reporter, cubic);
140
141 SkPath line;
142 line.moveTo(SK_Scalar1, SK_Scalar1);
143 line.lineTo(10 * SK_Scalar1, 10*SK_Scalar1);
144 check_close(reporter, line);
145 line.close();
146 check_close(reporter, line);
147
148 SkPath rect2;
149 rect2.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
150 rect2.close();
151 rect2.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
152 check_close(reporter, rect2);
153 rect2.close();
154 check_close(reporter, rect2);
155
156 SkPath oval3;
157 oval3.addOval(SkRect::MakeWH(SK_Scalar1*100,SK_Scalar1*100));
158 oval3.close();
159 oval3.addOval(SkRect::MakeWH(SK_Scalar1*200,SK_Scalar1*200));
160 check_close(reporter, oval3);
161 oval3.close();
162 check_close(reporter, oval3);
163
164 SkPath moves;
165 moves.moveTo(SK_Scalar1, SK_Scalar1);
166 moves.moveTo(5 * SK_Scalar1, SK_Scalar1);
167 moves.moveTo(SK_Scalar1, 10 * SK_Scalar1);
168 moves.moveTo(10 *SK_Scalar1, SK_Scalar1);
169 check_close(reporter, moves);
reed@google.com55b5f4b2011-09-07 12:23:41 +0000170
171 stroke_tiny_cubic();
bsalomon@google.comb3b8dfa2011-07-13 17:44:36 +0000172}
173
reed@google.com7c424812011-05-15 04:38:34 +0000174static void check_convexity(skiatest::Reporter* reporter, const SkPath& path,
175 SkPath::Convexity expected) {
176 SkPath::Convexity c = SkPath::ComputeConvexity(path);
177 REPORTER_ASSERT(reporter, c == expected);
178}
179
180static void test_convexity2(skiatest::Reporter* reporter) {
181 SkPath pt;
182 pt.moveTo(0, 0);
183 pt.close();
reed@google.comb54455e2011-05-16 14:16:04 +0000184 check_convexity(reporter, pt, SkPath::kConvex_Convexity);
reed@google.com7c424812011-05-15 04:38:34 +0000185
186 SkPath line;
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000187 line.moveTo(12*SK_Scalar1, 20*SK_Scalar1);
188 line.lineTo(-12*SK_Scalar1, -20*SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000189 line.close();
reed@google.comb54455e2011-05-16 14:16:04 +0000190 check_convexity(reporter, pt, SkPath::kConvex_Convexity);
reed@google.com7c424812011-05-15 04:38:34 +0000191
192 SkPath triLeft;
193 triLeft.moveTo(0, 0);
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000194 triLeft.lineTo(SK_Scalar1, 0);
195 triLeft.lineTo(SK_Scalar1, SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000196 triLeft.close();
197 check_convexity(reporter, triLeft, SkPath::kConvex_Convexity);
198
199 SkPath triRight;
200 triRight.moveTo(0, 0);
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000201 triRight.lineTo(-SK_Scalar1, 0);
202 triRight.lineTo(SK_Scalar1, SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000203 triRight.close();
204 check_convexity(reporter, triRight, SkPath::kConvex_Convexity);
205
206 SkPath square;
207 square.moveTo(0, 0);
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000208 square.lineTo(SK_Scalar1, 0);
209 square.lineTo(SK_Scalar1, SK_Scalar1);
210 square.lineTo(0, SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000211 square.close();
212 check_convexity(reporter, square, SkPath::kConvex_Convexity);
213
214 SkPath redundantSquare;
215 redundantSquare.moveTo(0, 0);
216 redundantSquare.lineTo(0, 0);
217 redundantSquare.lineTo(0, 0);
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000218 redundantSquare.lineTo(SK_Scalar1, 0);
219 redundantSquare.lineTo(SK_Scalar1, 0);
220 redundantSquare.lineTo(SK_Scalar1, 0);
221 redundantSquare.lineTo(SK_Scalar1, SK_Scalar1);
222 redundantSquare.lineTo(SK_Scalar1, SK_Scalar1);
223 redundantSquare.lineTo(SK_Scalar1, SK_Scalar1);
224 redundantSquare.lineTo(0, SK_Scalar1);
225 redundantSquare.lineTo(0, SK_Scalar1);
226 redundantSquare.lineTo(0, SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000227 redundantSquare.close();
228 check_convexity(reporter, redundantSquare, SkPath::kConvex_Convexity);
229
230 SkPath bowTie;
231 bowTie.moveTo(0, 0);
232 bowTie.lineTo(0, 0);
233 bowTie.lineTo(0, 0);
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000234 bowTie.lineTo(SK_Scalar1, SK_Scalar1);
235 bowTie.lineTo(SK_Scalar1, SK_Scalar1);
236 bowTie.lineTo(SK_Scalar1, SK_Scalar1);
237 bowTie.lineTo(SK_Scalar1, 0);
238 bowTie.lineTo(SK_Scalar1, 0);
239 bowTie.lineTo(SK_Scalar1, 0);
240 bowTie.lineTo(0, SK_Scalar1);
241 bowTie.lineTo(0, SK_Scalar1);
242 bowTie.lineTo(0, SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000243 bowTie.close();
244 check_convexity(reporter, bowTie, SkPath::kConcave_Convexity);
245
246 SkPath spiral;
247 spiral.moveTo(0, 0);
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000248 spiral.lineTo(100*SK_Scalar1, 0);
249 spiral.lineTo(100*SK_Scalar1, 100*SK_Scalar1);
250 spiral.lineTo(0, 100*SK_Scalar1);
251 spiral.lineTo(0, 50*SK_Scalar1);
252 spiral.lineTo(50*SK_Scalar1, 50*SK_Scalar1);
253 spiral.lineTo(50*SK_Scalar1, 75*SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000254 spiral.close();
reed@google.com85b6e392011-05-15 20:25:17 +0000255 check_convexity(reporter, spiral, SkPath::kConcave_Convexity);
reed@google.com7c424812011-05-15 04:38:34 +0000256
257 SkPath dent;
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000258 dent.moveTo(0, 0);
259 dent.lineTo(100*SK_Scalar1, 100*SK_Scalar1);
260 dent.lineTo(0, 100*SK_Scalar1);
261 dent.lineTo(-50*SK_Scalar1, 200*SK_Scalar1);
262 dent.lineTo(-200*SK_Scalar1, 100*SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000263 dent.close();
264 check_convexity(reporter, dent, SkPath::kConcave_Convexity);
265}
266
reed@android.com6b82d1a2009-06-03 02:35:01 +0000267static void check_convex_bounds(skiatest::Reporter* reporter, const SkPath& p,
268 const SkRect& bounds) {
269 REPORTER_ASSERT(reporter, p.isConvex());
270 REPORTER_ASSERT(reporter, p.getBounds() == bounds);
reed@google.com62047cf2011-02-07 19:39:09 +0000271
reed@android.com6b82d1a2009-06-03 02:35:01 +0000272 SkPath p2(p);
273 REPORTER_ASSERT(reporter, p2.isConvex());
274 REPORTER_ASSERT(reporter, p2.getBounds() == bounds);
275
276 SkPath other;
277 other.swap(p2);
278 REPORTER_ASSERT(reporter, other.isConvex());
279 REPORTER_ASSERT(reporter, other.getBounds() == bounds);
280}
281
reed@google.com04863fa2011-05-15 04:08:24 +0000282static void setFromString(SkPath* path, const char str[]) {
283 bool first = true;
284 while (str) {
285 SkScalar x, y;
286 str = SkParse::FindScalar(str, &x);
287 if (NULL == str) {
288 break;
289 }
290 str = SkParse::FindScalar(str, &y);
291 SkASSERT(str);
292 if (first) {
293 path->moveTo(x, y);
294 first = false;
295 } else {
296 path->lineTo(x, y);
297 }
298 }
299}
300
301static void test_convexity(skiatest::Reporter* reporter) {
reed@google.com04863fa2011-05-15 04:08:24 +0000302 static const SkPath::Convexity C = SkPath::kConcave_Convexity;
303 static const SkPath::Convexity V = SkPath::kConvex_Convexity;
304
305 SkPath path;
306
reed@google.comb54455e2011-05-16 14:16:04 +0000307 REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
reed@google.com04863fa2011-05-15 04:08:24 +0000308 path.addCircle(0, 0, 10);
309 REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
310 path.addCircle(0, 0, 10); // 2nd circle
311 REPORTER_ASSERT(reporter, C == SkPath::ComputeConvexity(path));
312 path.reset();
313 path.addRect(0, 0, 10, 10, SkPath::kCCW_Direction);
314 REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
315 path.reset();
316 path.addRect(0, 0, 10, 10, SkPath::kCW_Direction);
317 REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
318
319 static const struct {
320 const char* fPathStr;
321 SkPath::Convexity fExpectedConvexity;
322 } gRec[] = {
reed@google.comb54455e2011-05-16 14:16:04 +0000323 { "", SkPath::kConvex_Convexity },
324 { "0 0", SkPath::kConvex_Convexity },
325 { "0 0 10 10", SkPath::kConvex_Convexity },
reed@google.com85b6e392011-05-15 20:25:17 +0000326 { "0 0 10 10 20 20 0 0 10 10", SkPath::kConcave_Convexity },
reed@google.com04863fa2011-05-15 04:08:24 +0000327 { "0 0 10 10 10 20", SkPath::kConvex_Convexity },
328 { "0 0 10 10 10 0", SkPath::kConvex_Convexity },
329 { "0 0 10 10 10 0 0 10", SkPath::kConcave_Convexity },
330 { "0 0 10 0 0 10 -10 -10", SkPath::kConcave_Convexity },
331 };
332
333 for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
334 SkPath path;
335 setFromString(&path, gRec[i].fPathStr);
336 SkPath::Convexity c = SkPath::ComputeConvexity(path);
337 REPORTER_ASSERT(reporter, c == gRec[i].fExpectedConvexity);
338 }
339}
340
caryclark@google.comf1316942011-07-26 19:54:45 +0000341// Simple isRect test is inline TestPath, below.
342// test_isRect provides more extensive testing.
343static void test_isRect(skiatest::Reporter* reporter) {
344 // passing tests (all moveTo / lineTo...
345 SkPoint r1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
346 SkPoint r2[] = {{1, 0}, {1, 1}, {0, 1}, {0, 0}};
347 SkPoint r3[] = {{1, 1}, {0, 1}, {0, 0}, {1, 0}};
348 SkPoint r4[] = {{0, 1}, {0, 0}, {1, 0}, {1, 1}};
349 SkPoint r5[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}};
350 SkPoint r6[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
351 SkPoint r7[] = {{1, 1}, {1, 0}, {0, 0}, {0, 1}};
352 SkPoint r8[] = {{1, 0}, {0, 0}, {0, 1}, {1, 1}};
353 SkPoint r9[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
354 SkPoint ra[] = {{0, 0}, {0, .5f}, {0, 1}, {.5f, 1}, {1, 1}, {1, .5f},
355 {1, 0}, {.5f, 0}};
356 SkPoint rb[] = {{0, 0}, {.5f, 0}, {1, 0}, {1, .5f}, {1, 1}, {.5f, 1},
357 {0, 1}, {0, .5f}};
358 SkPoint rc[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}};
359 SkPoint rd[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}};
360 SkPoint re[] = {{0, 0}, {1, 0}, {1, 0}, {1, 1}, {0, 1}};
361
362 // failing tests
363 SkPoint f1[] = {{0, 0}, {1, 0}, {1, 1}}; // too few points
364 SkPoint f2[] = {{0, 0}, {1, 1}, {0, 1}, {1, 0}}; // diagonal
365 SkPoint f3[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}, {1, 0}}; // wraps
366 SkPoint f4[] = {{0, 0}, {1, 0}, {0, 0}, {1, 0}, {1, 1}, {0, 1}}; // backs up
367 SkPoint f5[] = {{0, 0}, {1, 0}, {1, 1}, {2, 0}}; // end overshoots
368 SkPoint f6[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 2}}; // end overshoots
369 SkPoint f7[] = {{0, 0}, {1, 0}, {1, 1}, {0, 2}}; // end overshoots
370 SkPoint f8[] = {{0, 0}, {1, 0}, {1, 1}, {1, 0}}; // 'L'
371
372 // failing, no close
373 SkPoint c1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}}; // close doesn't match
374 SkPoint c2[] = {{0, 0}, {1, 0}, {1, 2}, {0, 2}, {0, 1}}; // ditto
375
376 size_t testLen[] = {
377 sizeof(r1), sizeof(r2), sizeof(r3), sizeof(r4), sizeof(r5), sizeof(r6),
378 sizeof(r7), sizeof(r8), sizeof(r9), sizeof(ra), sizeof(rb), sizeof(rc),
379 sizeof(rd), sizeof(re),
380 sizeof(f1), sizeof(f2), sizeof(f3), sizeof(f4), sizeof(f5), sizeof(f6),
381 sizeof(f7), sizeof(f8),
382 sizeof(c1), sizeof(c2)
383 };
384 SkPoint* tests[] = {
385 r1, r2, r3, r4, r5, r6, r7, r8, r9, ra, rb, rc, rd, re,
386 f1, f2, f3, f4, f5, f6, f7, f8,
387 c1, c2
388 };
389 SkPoint* lastPass = re;
390 SkPoint* lastClose = f8;
391 bool fail = false;
392 bool close = true;
393 const size_t testCount = sizeof(tests) / sizeof(tests[0]);
394 size_t index;
395 for (size_t testIndex = 0; testIndex < testCount; ++testIndex) {
396 SkPath path;
397 path.moveTo(tests[testIndex][0].fX, tests[testIndex][0].fY);
398 for (index = 1; index < testLen[testIndex] / sizeof(SkPoint); ++index) {
399 path.lineTo(tests[testIndex][index].fX, tests[testIndex][index].fY);
400 }
401 if (close) {
402 path.close();
403 }
404 REPORTER_ASSERT(reporter, fail ^ path.isRect(0));
405 if (tests[testIndex] == lastPass) {
406 fail = true;
407 }
408 if (tests[testIndex] == lastClose) {
409 close = false;
410 }
411 }
412
413 // fail, close then line
414 SkPath path1;
415 path1.moveTo(r1[0].fX, r1[0].fY);
416 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
417 path1.lineTo(r1[index].fX, r1[index].fY);
418 }
419 path1.close();
420 path1.lineTo(1, 0);
421 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
422
423 // fail, move in the middle
424 path1.reset();
425 path1.moveTo(r1[0].fX, r1[0].fY);
426 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
427 if (index == 2) {
428 path1.moveTo(1, .5f);
429 }
430 path1.lineTo(r1[index].fX, r1[index].fY);
431 }
432 path1.close();
433 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
434
435 // fail, move on the edge
436 path1.reset();
437 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
438 path1.moveTo(r1[index - 1].fX, r1[index - 1].fY);
439 path1.lineTo(r1[index].fX, r1[index].fY);
440 }
441 path1.close();
442 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
443
444 // fail, quad
445 path1.reset();
446 path1.moveTo(r1[0].fX, r1[0].fY);
447 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
448 if (index == 2) {
449 path1.quadTo(1, .5f, 1, .5f);
450 }
451 path1.lineTo(r1[index].fX, r1[index].fY);
452 }
453 path1.close();
454 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
455
456 // fail, cubic
457 path1.reset();
458 path1.moveTo(r1[0].fX, r1[0].fY);
459 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
460 if (index == 2) {
461 path1.cubicTo(1, .5f, 1, .5f, 1, .5f);
462 }
463 path1.lineTo(r1[index].fX, r1[index].fY);
464 }
465 path1.close();
466 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
467}
468
reed@google.com53effc52011-09-21 19:05:12 +0000469static void test_flattening(skiatest::Reporter* reporter) {
470 SkPath p;
471
472 static const SkPoint pts[] = {
473 { 0, 0 },
474 { SkIntToScalar(10), SkIntToScalar(10) },
475 { SkIntToScalar(20), SkIntToScalar(10) }, { SkIntToScalar(20), 0 },
476 { 0, 0 }, { 0, SkIntToScalar(10) }, { SkIntToScalar(1), SkIntToScalar(10) }
477 };
478 p.moveTo(pts[0]);
479 p.lineTo(pts[1]);
480 p.quadTo(pts[2], pts[3]);
481 p.cubicTo(pts[4], pts[5], pts[6]);
482
483 SkWriter32 writer(100);
484 p.flatten(writer);
485 size_t size = writer.size();
486 SkAutoMalloc storage(size);
487 writer.flatten(storage.get());
488 SkReader32 reader(storage.get(), size);
489
490 SkPath p1;
491 REPORTER_ASSERT(reporter, p1 != p);
492 p1.unflatten(reader);
493 REPORTER_ASSERT(reporter, p1 == p);
494}
495
496static void test_transform(skiatest::Reporter* reporter) {
497 SkPath p, p1;
498
499 static const SkPoint pts[] = {
500 { 0, 0 },
501 { SkIntToScalar(10), SkIntToScalar(10) },
502 { SkIntToScalar(20), SkIntToScalar(10) }, { SkIntToScalar(20), 0 },
503 { 0, 0 }, { 0, SkIntToScalar(10) }, { SkIntToScalar(1), SkIntToScalar(10) }
504 };
505 p.moveTo(pts[0]);
506 p.lineTo(pts[1]);
507 p.quadTo(pts[2], pts[3]);
508 p.cubicTo(pts[4], pts[5], pts[6]);
509
510 SkMatrix matrix;
511 matrix.reset();
512 p.transform(matrix, &p1);
513 REPORTER_ASSERT(reporter, p == p1);
514
515 matrix.setScale(SK_Scalar1 * 2, SK_Scalar1 * 3);
516 p.transform(matrix, &p1);
517 SkPoint pts1[7];
518 int count = p1.getPoints(pts1, 7);
519 REPORTER_ASSERT(reporter, 7 == count);
520 for (int i = 0; i < count; ++i) {
521 SkPoint newPt = SkPoint::Make(pts[i].fX * 2, pts[i].fY * 3);
522 REPORTER_ASSERT(reporter, newPt == pts1[i]);
523 }
524}
525
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000526static void test_zero_length_paths(skiatest::Reporter* reporter) {
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000527 SkPath p;
528 SkPoint pt;
529 SkRect bounds;
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000530
531 // Lone moveTo case
532 p.moveTo(SK_Scalar1, SK_Scalar1);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000533 REPORTER_ASSERT(reporter, !p.isEmpty());
534 REPORTER_ASSERT(reporter, 1 == p.countPoints());
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000535 p.getLastPt(&pt);
536 REPORTER_ASSERT(reporter, pt.fX == SK_Scalar1);
537 REPORTER_ASSERT(reporter, pt.fY == SK_Scalar1);
538 bounds.set(0, 0, 0, 0);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000539 REPORTER_ASSERT(reporter, bounds == p.getBounds());
540
541 // MoveTo-MoveTo case
542 p.moveTo(SK_Scalar1*2, SK_Scalar1);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000543 REPORTER_ASSERT(reporter, !p.isEmpty());
544 REPORTER_ASSERT(reporter, 2 == p.countPoints());
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000545 p.getLastPt(&pt);
546 REPORTER_ASSERT(reporter, pt.fX == SK_Scalar1*2);
547 REPORTER_ASSERT(reporter, pt.fY == SK_Scalar1);
548 bounds.set(SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000549 REPORTER_ASSERT(reporter, bounds == p.getBounds());
550
551 // moveTo-close case
552 p.reset();
553 p.moveTo(SK_Scalar1, SK_Scalar1);
554 p.close();
555 bounds.set(0, 0, 0, 0);
556 REPORTER_ASSERT(reporter, !p.isEmpty());
557 REPORTER_ASSERT(reporter, 1 == p.countPoints());
558 REPORTER_ASSERT(reporter, bounds == p.getBounds());
559
560 // moveTo-close-moveTo-close case
561 p.moveTo(SK_Scalar1*2, SK_Scalar1);
562 p.close();
schenney@chromium.org32879492011-12-20 15:33:11 +0000563 bounds.set(SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000564 REPORTER_ASSERT(reporter, !p.isEmpty());
565 REPORTER_ASSERT(reporter, 2 == p.countPoints());
566 REPORTER_ASSERT(reporter, bounds == p.getBounds());
567
568 // moveTo-line case
569 p.reset();
570 p.moveTo(SK_Scalar1, SK_Scalar1);
571 p.lineTo(SK_Scalar1, SK_Scalar1);
572 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
573 REPORTER_ASSERT(reporter, !p.isEmpty());
574 REPORTER_ASSERT(reporter, 2 == p.countPoints());
575 REPORTER_ASSERT(reporter, bounds == p.getBounds());
576
577 // moveTo-lineTo-moveTo-lineTo case
578 p.moveTo(SK_Scalar1*2, SK_Scalar1);
579 p.lineTo(SK_Scalar1*2, SK_Scalar1);
580 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
581 REPORTER_ASSERT(reporter, !p.isEmpty());
582 REPORTER_ASSERT(reporter, 4 == p.countPoints());
583 REPORTER_ASSERT(reporter, bounds == p.getBounds());
584
585 // moveTo-line-close case
586 p.reset();
587 p.moveTo(SK_Scalar1, SK_Scalar1);
588 p.lineTo(SK_Scalar1, SK_Scalar1);
589 p.close();
590 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
591 REPORTER_ASSERT(reporter, !p.isEmpty());
592 REPORTER_ASSERT(reporter, 2 == p.countPoints());
593 REPORTER_ASSERT(reporter, bounds == p.getBounds());
594
595 // moveTo-line-close-moveTo-line-close case
596 p.moveTo(SK_Scalar1*2, SK_Scalar1);
597 p.lineTo(SK_Scalar1*2, SK_Scalar1);
598 p.close();
599 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
600 REPORTER_ASSERT(reporter, !p.isEmpty());
601 REPORTER_ASSERT(reporter, 4 == p.countPoints());
602 REPORTER_ASSERT(reporter, bounds == p.getBounds());
603
604 // moveTo-quadTo case
605 p.reset();
606 p.moveTo(SK_Scalar1, SK_Scalar1);
607 p.quadTo(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
608 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
609 REPORTER_ASSERT(reporter, !p.isEmpty());
610 REPORTER_ASSERT(reporter, 3 == p.countPoints());
611 REPORTER_ASSERT(reporter, bounds == p.getBounds());
612
613 // moveTo-quadTo-close case
614 p.close();
615 REPORTER_ASSERT(reporter, !p.isEmpty());
616 REPORTER_ASSERT(reporter, 3 == p.countPoints());
617 REPORTER_ASSERT(reporter, bounds == p.getBounds());
618
619 // moveTo-quadTo-moveTo-quadTo case
620 p.reset();
621 p.moveTo(SK_Scalar1, SK_Scalar1);
622 p.quadTo(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
623 p.moveTo(SK_Scalar1*2, SK_Scalar1);
624 p.quadTo(SK_Scalar1*2, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
625 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
626 REPORTER_ASSERT(reporter, !p.isEmpty());
627 REPORTER_ASSERT(reporter, 6 == p.countPoints());
628 REPORTER_ASSERT(reporter, bounds == p.getBounds());
629
630 // moveTo-cubicTo case
631 p.reset();
632 p.moveTo(SK_Scalar1, SK_Scalar1);
633 p.cubicTo(SK_Scalar1, SK_Scalar1,
634 SK_Scalar1, SK_Scalar1,
635 SK_Scalar1, SK_Scalar1);
636 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
637 REPORTER_ASSERT(reporter, !p.isEmpty());
638 REPORTER_ASSERT(reporter, 4 == p.countPoints());
639 REPORTER_ASSERT(reporter, bounds == p.getBounds());
640
641 // moveTo-quadTo-close case
642 p.close();
643 REPORTER_ASSERT(reporter, !p.isEmpty());
644 REPORTER_ASSERT(reporter, 4 == p.countPoints());
645 REPORTER_ASSERT(reporter, bounds == p.getBounds());
646
647 // moveTo-quadTo-moveTo-quadTo case
648 p.reset();
649 p.moveTo(SK_Scalar1, SK_Scalar1);
650 p.cubicTo(SK_Scalar1, SK_Scalar1,
651 SK_Scalar1, SK_Scalar1,
652 SK_Scalar1, SK_Scalar1);
653 p.moveTo(SK_Scalar1*2, SK_Scalar1);
654 p.cubicTo(SK_Scalar1*2, SK_Scalar1,
655 SK_Scalar1*2, SK_Scalar1,
656 SK_Scalar1*2, SK_Scalar1);
657 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
658 REPORTER_ASSERT(reporter, !p.isEmpty());
659 REPORTER_ASSERT(reporter, 8 == p.countPoints());
660 REPORTER_ASSERT(reporter, bounds == p.getBounds());
661}
662
663struct SegmentInfo {
664 SkPath fPath;
665 int fPointCount;
666};
667
reed@google.com10296cc2011-09-21 12:29:05 +0000668#define kCurveSegmentMask (SkPath::kQuad_SegmentMask | SkPath::kCubic_SegmentMask)
669
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000670static void test_segment_masks(skiatest::Reporter* reporter) {
671 SkPath p;
672 p.moveTo(0, 0);
673 p.quadTo(100, 100, 200, 200);
674 REPORTER_ASSERT(reporter, SkPath::kQuad_SegmentMask == p.getSegmentMasks());
675 REPORTER_ASSERT(reporter, !p.isEmpty());
676 p.cubicTo(100, 100, 200, 200, 300, 300);
677 REPORTER_ASSERT(reporter, kCurveSegmentMask == p.getSegmentMasks());
678 REPORTER_ASSERT(reporter, !p.isEmpty());
679 p.reset();
680 p.moveTo(0, 0);
681 p.cubicTo(100, 100, 200, 200, 300, 300);
682 REPORTER_ASSERT(reporter, SkPath::kCubic_SegmentMask == p.getSegmentMasks());
683 REPORTER_ASSERT(reporter, !p.isEmpty());
684}
685
686static void test_iter(skiatest::Reporter* reporter) {
687 SkPath p;
688 SkPoint pts[4];
689
690 // Test an iterator with no path
691 SkPath::Iter noPathIter;
692 REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
693 // Test that setting an empty path works
694 noPathIter.setPath(p, false);
695 REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
696 // Test that close path makes no difference for an empty path
697 noPathIter.setPath(p, true);
698 REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
699
700 // Test an iterator with an initial empty path
701 SkPath::Iter iter(p, false);
702 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
703
704 // Test that close path makes no difference
705 SkPath::Iter forceCloseIter(p, true);
706 REPORTER_ASSERT(reporter, forceCloseIter.next(pts) == SkPath::kDone_Verb);
707
708 // Test that a move-only path produces nothing when iterated.
709 p.moveTo(SK_Scalar1, 0);
710 iter.setPath(p, false);
711 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
712
713 // No matter how many moves we add, we should still get nothing back.
714 p.moveTo(SK_Scalar1*2, 0);
715 p.moveTo(SK_Scalar1*3, 0);
716 p.moveTo(SK_Scalar1*4, 0);
717 p.moveTo(SK_Scalar1*5, 0);
718 iter.setPath(p, false);
719 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
720
721 // Nor should force closing
722 forceCloseIter.setPath(p, true);
723 REPORTER_ASSERT(reporter, forceCloseIter.next(pts) == SkPath::kDone_Verb);
724
725 // Initial closes should be ignored
726 p.reset();
727 p.close();
728 iter.setPath(p, false);
729 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
730 // Even if force closed
731 forceCloseIter.setPath(p, true);
732 REPORTER_ASSERT(reporter, forceCloseIter.next(pts) == SkPath::kDone_Verb);
733
734 // Move/close sequences should also be ignored
735 p.reset();
736 p.close();
737 p.moveTo(SK_Scalar1, 0);
738 p.close();
739 p.close();
740 p.moveTo(SK_Scalar1*2, 0);
741 p.close();
742 p.moveTo(SK_Scalar1*3, 0);
743 p.moveTo(SK_Scalar1*4, 0);
744 p.close();
745 iter.setPath(p, false);
746 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
747 // Even if force closed
748 forceCloseIter.setPath(p, true);
749 REPORTER_ASSERT(reporter, forceCloseIter.next(pts) == SkPath::kDone_Verb);
750
751 // The GM degeneratesegments.cpp test is more extensive
752}
753
754static void test_raw_iter(skiatest::Reporter* reporter) {
755 SkPath p;
756 SkPoint pts[4];
757
758 // Test an iterator with no path
759 SkPath::RawIter noPathIter;
760 REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
761 // Test that setting an empty path works
762 noPathIter.setPath(p);
763 REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
764
765 // Test an iterator with an initial empty path
766 SkPath::RawIter iter(p);
767 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
768
769 // Test that a move-only path returns the move.
770 p.moveTo(SK_Scalar1, 0);
771 iter.setPath(p);
772 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
773 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
774 REPORTER_ASSERT(reporter, pts[0].fY == 0);
775 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
776
777 // No matter how many moves we add, we should get them all back
778 p.moveTo(SK_Scalar1*2, SK_Scalar1);
779 p.moveTo(SK_Scalar1*3, SK_Scalar1*2);
780 iter.setPath(p);
781 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
782 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
783 REPORTER_ASSERT(reporter, pts[0].fY == 0);
784 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
785 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2);
786 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1);
787 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
788 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*3);
789 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*2);
790 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
791
792 // Initial close is never ever stored
793 p.reset();
794 p.close();
795 iter.setPath(p);
796 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
797
798 // Move/close sequences
799 p.reset();
800 p.close(); // Not stored, no purpose
801 p.moveTo(SK_Scalar1, 0);
802 p.close();
803 p.close(); // Not stored, no purpose
804 p.moveTo(SK_Scalar1*2, SK_Scalar1);
805 p.close();
806 p.moveTo(SK_Scalar1*3, SK_Scalar1*2);
807 p.moveTo(SK_Scalar1*4, SK_Scalar1*3);
808 p.close();
809 iter.setPath(p);
810 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
811 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
812 REPORTER_ASSERT(reporter, pts[0].fY == 0);
813 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kClose_Verb);
814 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
815 REPORTER_ASSERT(reporter, pts[0].fY == 0);
816 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
817 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2);
818 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1);
819 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kClose_Verb);
820 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2);
821 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1);
822 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
823 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*3);
824 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*2);
825 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
826 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*4);
827 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*3);
828 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kClose_Verb);
829 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*4);
830 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*3);
831 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
832
833 // Generate random paths and verify
834 SkPoint randomPts[25];
835 for (int i = 0; i < 5; ++i) {
836 for (int j = 0; j < 5; ++j) {
837 randomPts[i*5+j].set(SK_Scalar1*i, SK_Scalar1*j);
838 }
839 }
840
841 // Max of 10 segments, max 3 points per segment
842 SkRandom rand(9876543);
843 SkPoint expectedPts[31]; // May have leading moveTo
844 SkPath::Verb expectedVerbs[11]; // May have leading moveTo
845 SkPath::Verb nextVerb;
846 for (int i = 0; i < 500; ++i) {
847 p.reset();
848 bool lastWasClose = true;
849 bool haveMoveTo = false;
850 int numPoints = 0;
851 int numVerbs = (rand.nextU() >> 16) % 10;
852 int numIterVerbs = 0;
853 for (int j = 0; j < numVerbs; ++j) {
854 do {
855 nextVerb = static_cast<SkPath::Verb>((rand.nextU() >> 16) % SkPath::kDone_Verb);
856 } while (lastWasClose && nextVerb == SkPath::kClose_Verb);
857 int numRequiredPts;
858 switch (nextVerb) {
859 case SkPath::kMove_Verb:
860 expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
861 p.moveTo(expectedPts[numPoints]);
862 numPoints += 1;
863 lastWasClose = false;
864 haveMoveTo = true;
865 break;
866 case SkPath::kLine_Verb:
867 if (!haveMoveTo) {
868 expectedPts[numPoints++].set(0, 0);
869 expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
870 haveMoveTo = true;
871 }
872 expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
873 p.lineTo(expectedPts[numPoints]);
874 numPoints += 1;
875 lastWasClose = false;
876 break;
877 case SkPath::kQuad_Verb:
878 if (!haveMoveTo) {
879 expectedPts[numPoints++].set(0, 0);
880 expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
881 haveMoveTo = true;
882 }
883 expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
884 expectedPts[numPoints + 1] = randomPts[(rand.nextU() >> 16) % 25];
885 p.quadTo(expectedPts[numPoints], expectedPts[numPoints + 1]);
886 numPoints += 2;
887 lastWasClose = false;
888 break;
889 case SkPath::kCubic_Verb:
890 if (!haveMoveTo) {
891 expectedPts[numPoints++].set(0, 0);
892 expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
893 haveMoveTo = true;
894 }
895 expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
896 expectedPts[numPoints + 1] = randomPts[(rand.nextU() >> 16) % 25];
897 expectedPts[numPoints + 2] = randomPts[(rand.nextU() >> 16) % 25];
898 p.cubicTo(expectedPts[numPoints], expectedPts[numPoints + 1],
899 expectedPts[numPoints + 2]);
900 numPoints += 3;
901 lastWasClose = false;
902 break;
903 case SkPath::kClose_Verb:
904 p.close();
905 lastWasClose = true;
906 break;
907 default:;
908 }
909 expectedVerbs[numIterVerbs++] = nextVerb;
910 }
911
912 iter.setPath(p);
913 numVerbs = numIterVerbs;
914 numIterVerbs = 0;
915 int numIterPts = 0;
916 SkPoint lastMoveTo;
917 SkPoint lastPt;
918 lastMoveTo.set(0, 0);
919 lastPt.set(0, 0);
920 while ((nextVerb = iter.next(pts)) != SkPath::kDone_Verb) {
921 REPORTER_ASSERT(reporter, nextVerb == expectedVerbs[numIterVerbs]);
922 numIterVerbs++;
923 switch (nextVerb) {
924 case SkPath::kMove_Verb:
925 REPORTER_ASSERT(reporter, numIterPts < numPoints);
926 REPORTER_ASSERT(reporter, pts[0] == expectedPts[numIterPts]);
927 lastPt = lastMoveTo = pts[0];
928 numIterPts += 1;
929 break;
930 case SkPath::kLine_Verb:
931 REPORTER_ASSERT(reporter, numIterPts < numPoints + 1);
932 REPORTER_ASSERT(reporter, pts[0] == lastPt);
933 REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]);
934 lastPt = pts[1];
935 numIterPts += 1;
936 break;
937 case SkPath::kQuad_Verb:
938 REPORTER_ASSERT(reporter, numIterPts < numPoints + 2);
939 REPORTER_ASSERT(reporter, pts[0] == lastPt);
940 REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]);
941 REPORTER_ASSERT(reporter, pts[2] == expectedPts[numIterPts + 1]);
942 lastPt = pts[2];
943 numIterPts += 2;
944 break;
945 case SkPath::kCubic_Verb:
946 REPORTER_ASSERT(reporter, numIterPts < numPoints + 3);
947 REPORTER_ASSERT(reporter, pts[0] == lastPt);
948 REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]);
949 REPORTER_ASSERT(reporter, pts[2] == expectedPts[numIterPts + 1]);
950 REPORTER_ASSERT(reporter, pts[3] == expectedPts[numIterPts + 2]);
951 lastPt = pts[3];
952 numIterPts += 3;
953 break;
954 case SkPath::kClose_Verb:
955 REPORTER_ASSERT(reporter, pts[0] == lastMoveTo);
956 lastPt = lastMoveTo;
957 break;
958 default:;
959 }
960 }
961 REPORTER_ASSERT(reporter, numIterPts == numPoints);
962 REPORTER_ASSERT(reporter, numIterVerbs == numVerbs);
963 }
964}
965
reed@google.com04863fa2011-05-15 04:08:24 +0000966void TestPath(skiatest::Reporter* reporter);
967void TestPath(skiatest::Reporter* reporter) {
reed@android.com60bc6d52010-02-11 11:09:39 +0000968 {
969 SkSize size;
970 size.fWidth = 3.4f;
971 size.width();
972 size = SkSize::Make(3,4);
973 SkISize isize = SkISize::Make(3,4);
974 }
975
976 SkTSize<SkScalar>::Make(3,4);
977
reed@android.com3abec1d2009-03-02 05:36:20 +0000978 SkPath p, p2;
979 SkRect bounds, bounds2;
reed@android.com80e39a72009-04-02 16:59:40 +0000980
reed@android.com3abec1d2009-03-02 05:36:20 +0000981 REPORTER_ASSERT(reporter, p.isEmpty());
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000982 REPORTER_ASSERT(reporter, 0 == p.countPoints());
reed@google.com10296cc2011-09-21 12:29:05 +0000983 REPORTER_ASSERT(reporter, 0 == p.getSegmentMasks());
reed@google.comb54455e2011-05-16 14:16:04 +0000984 REPORTER_ASSERT(reporter, p.isConvex());
reed@android.com3abec1d2009-03-02 05:36:20 +0000985 REPORTER_ASSERT(reporter, p.getFillType() == SkPath::kWinding_FillType);
986 REPORTER_ASSERT(reporter, !p.isInverseFillType());
987 REPORTER_ASSERT(reporter, p == p2);
988 REPORTER_ASSERT(reporter, !(p != p2));
989
reed@android.comd252db02009-04-01 18:31:44 +0000990 REPORTER_ASSERT(reporter, p.getBounds().isEmpty());
reed@android.com80e39a72009-04-02 16:59:40 +0000991
reed@android.com3abec1d2009-03-02 05:36:20 +0000992 bounds.set(0, 0, SK_Scalar1, SK_Scalar1);
reed@android.com6b82d1a2009-06-03 02:35:01 +0000993
reed@android.com6b82d1a2009-06-03 02:35:01 +0000994 p.addRoundRect(bounds, SK_Scalar1, SK_Scalar1);
995 check_convex_bounds(reporter, p, bounds);
reed@google.com10296cc2011-09-21 12:29:05 +0000996 // we have quads or cubics
997 REPORTER_ASSERT(reporter, p.getSegmentMasks() & kCurveSegmentMask);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000998 REPORTER_ASSERT(reporter, !p.isEmpty());
reed@google.com62047cf2011-02-07 19:39:09 +0000999
reed@android.com6b82d1a2009-06-03 02:35:01 +00001000 p.reset();
reed@google.com10296cc2011-09-21 12:29:05 +00001001 REPORTER_ASSERT(reporter, 0 == p.getSegmentMasks());
schenney@chromium.org4da06ab2011-12-20 15:14:18 +00001002 REPORTER_ASSERT(reporter, p.isEmpty());
reed@google.com10296cc2011-09-21 12:29:05 +00001003
reed@android.com6b82d1a2009-06-03 02:35:01 +00001004 p.addOval(bounds);
1005 check_convex_bounds(reporter, p, bounds);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +00001006 REPORTER_ASSERT(reporter, !p.isEmpty());
reed@google.com62047cf2011-02-07 19:39:09 +00001007
reed@android.com6b82d1a2009-06-03 02:35:01 +00001008 p.reset();
reed@android.com3abec1d2009-03-02 05:36:20 +00001009 p.addRect(bounds);
reed@android.com6b82d1a2009-06-03 02:35:01 +00001010 check_convex_bounds(reporter, p, bounds);
reed@google.com10296cc2011-09-21 12:29:05 +00001011 // we have only lines
1012 REPORTER_ASSERT(reporter, SkPath::kLine_SegmentMask == p.getSegmentMasks());
schenney@chromium.org4da06ab2011-12-20 15:14:18 +00001013 REPORTER_ASSERT(reporter, !p.isEmpty());
reed@android.com3abec1d2009-03-02 05:36:20 +00001014
1015 REPORTER_ASSERT(reporter, p != p2);
1016 REPORTER_ASSERT(reporter, !(p == p2));
1017
1018 // does getPoints return the right result
1019 REPORTER_ASSERT(reporter, p.getPoints(NULL, 5) == 4);
1020 SkPoint pts[4];
1021 int count = p.getPoints(pts, 4);
1022 REPORTER_ASSERT(reporter, count == 4);
1023 bounds2.set(pts, 4);
1024 REPORTER_ASSERT(reporter, bounds == bounds2);
reed@android.com80e39a72009-04-02 16:59:40 +00001025
reed@android.com3abec1d2009-03-02 05:36:20 +00001026 bounds.offset(SK_Scalar1*3, SK_Scalar1*4);
1027 p.offset(SK_Scalar1*3, SK_Scalar1*4);
reed@android.comd252db02009-04-01 18:31:44 +00001028 REPORTER_ASSERT(reporter, bounds == p.getBounds());
reed@android.com3abec1d2009-03-02 05:36:20 +00001029
reed@android.com3abec1d2009-03-02 05:36:20 +00001030 REPORTER_ASSERT(reporter, p.isRect(NULL));
caryclark@google.comf1316942011-07-26 19:54:45 +00001031 bounds2.setEmpty();
reed@android.com3abec1d2009-03-02 05:36:20 +00001032 REPORTER_ASSERT(reporter, p.isRect(&bounds2));
1033 REPORTER_ASSERT(reporter, bounds == bounds2);
reed@android.com80e39a72009-04-02 16:59:40 +00001034
reed@android.com3abec1d2009-03-02 05:36:20 +00001035 // now force p to not be a rect
1036 bounds.set(0, 0, SK_Scalar1/2, SK_Scalar1/2);
1037 p.addRect(bounds);
1038 REPORTER_ASSERT(reporter, !p.isRect(NULL));
caryclark@google.comf1316942011-07-26 19:54:45 +00001039 test_isRect(reporter);
reed@android.com3abec1d2009-03-02 05:36:20 +00001040
schenney@chromium.org4da06ab2011-12-20 15:14:18 +00001041 test_zero_length_paths(reporter);
reed@google.com04863fa2011-05-15 04:08:24 +00001042 test_convexity(reporter);
reed@google.com7c424812011-05-15 04:38:34 +00001043 test_convexity2(reporter);
bsalomon@google.comb3b8dfa2011-07-13 17:44:36 +00001044 test_close(reporter);
schenney@chromium.org6630d8d2012-01-04 21:05:51 +00001045 test_segment_masks(reporter);
reed@google.com53effc52011-09-21 19:05:12 +00001046 test_flattening(reporter);
1047 test_transform(reporter);
reed@google.com3563c9e2011-11-14 19:34:57 +00001048 test_bounds(reporter);
schenney@chromium.org6630d8d2012-01-04 21:05:51 +00001049 test_iter(reporter);
1050 test_raw_iter(reporter);
reed@android.com3abec1d2009-03-02 05:36:20 +00001051}
1052
1053#include "TestClassDef.h"
1054DEFINE_TESTCLASS("Path", PathTestClass, TestPath)