blob: 5e9a520f6332643610d0727ab0035b40afcd8bfb [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.com53effc52011-09-21 19:05:12 +000012#include "SkReader32.h"
reed@android.com60bc6d52010-02-11 11:09:39 +000013#include "SkSize.h"
reed@google.com53effc52011-09-21 19:05:12 +000014#include "SkWriter32.h"
reed@android.com3abec1d2009-03-02 05:36:20 +000015
reed@google.comffdb0182011-11-14 19:29:14 +000016static void add_rect(SkPath* path, const SkRect& r) {
17 path->moveTo(r.fLeft, r.fTop);
18 path->lineTo(r.fRight, r.fTop);
19 path->lineTo(r.fRight, r.fBottom);
20 path->lineTo(r.fLeft, r.fBottom);
21 path->close();
22}
23
24static void test_bounds(skiatest::Reporter* reporter) {
25 static const SkRect rects[] = {
reed@google.com3563c9e2011-11-14 19:34:57 +000026 { SkIntToScalar(10), SkIntToScalar(160), SkIntToScalar(610), SkIntToScalar(160) },
27 { SkIntToScalar(610), SkIntToScalar(160), SkIntToScalar(610), SkIntToScalar(199) },
28 { SkIntToScalar(10), SkIntToScalar(198), SkIntToScalar(610), SkIntToScalar(199) },
29 { SkIntToScalar(10), SkIntToScalar(160), SkIntToScalar(10), SkIntToScalar(199) },
reed@google.comffdb0182011-11-14 19:29:14 +000030 };
31
32 SkPath path0, path1;
33 for (size_t i = 0; i < SK_ARRAY_COUNT(rects); ++i) {
34 path0.addRect(rects[i]);
35 add_rect(&path1, rects[i]);
36 }
37
38 REPORTER_ASSERT(reporter, path0.getBounds() == path1.getBounds());
39}
40
reed@google.com55b5f4b2011-09-07 12:23:41 +000041static void stroke_cubic(const SkPoint pts[4]) {
42 SkPath path;
43 path.moveTo(pts[0]);
44 path.cubicTo(pts[1], pts[2], pts[3]);
45
46 SkPaint paint;
47 paint.setStyle(SkPaint::kStroke_Style);
48 paint.setStrokeWidth(SK_Scalar1 * 2);
49
50 SkPath fill;
51 paint.getFillPath(path, &fill);
52}
53
54// just ensure this can run w/o any SkASSERTS firing in the debug build
55// we used to assert due to differences in how we determine a degenerate vector
56// but that was fixed with the introduction of SkPoint::CanNormalize
57static void stroke_tiny_cubic() {
58 SkPoint p0[] = {
59 { 372.0f, 92.0f },
60 { 372.0f, 92.0f },
61 { 372.0f, 92.0f },
62 { 372.0f, 92.0f },
63 };
64
65 stroke_cubic(p0);
66
67 SkPoint p1[] = {
68 { 372.0f, 92.0f },
69 { 372.0007f, 92.000755f },
70 { 371.99927f, 92.003922f },
71 { 371.99826f, 92.003899f },
72 };
73
74 stroke_cubic(p1);
75}
76
bsalomon@google.comb3b8dfa2011-07-13 17:44:36 +000077static void check_close(skiatest::Reporter* reporter, const SkPath& path) {
78 for (int i = 0; i < 2; ++i) {
79 SkPath::Iter iter(path, (bool)i);
80 SkPoint mv;
81 SkPoint pts[4];
82 SkPath::Verb v;
83 int nMT = 0;
84 int nCL = 0;
tomhudson@google.com221db3c2011-07-28 21:10:29 +000085 mv.set(0, 0);
bsalomon@google.comb3b8dfa2011-07-13 17:44:36 +000086 while (SkPath::kDone_Verb != (v = iter.next(pts))) {
87 switch (v) {
88 case SkPath::kMove_Verb:
89 mv = pts[0];
90 ++nMT;
91 break;
92 case SkPath::kClose_Verb:
93 REPORTER_ASSERT(reporter, mv == pts[0]);
94 ++nCL;
95 break;
96 default:
97 break;
98 }
99 }
100 // if we force a close on the interator we should have a close
101 // for every moveTo
102 REPORTER_ASSERT(reporter, !i || nMT == nCL);
103 }
104}
105
106static void test_close(skiatest::Reporter* reporter) {
107 SkPath closePt;
108 closePt.moveTo(0, 0);
109 closePt.close();
110 check_close(reporter, closePt);
111
112 SkPath openPt;
113 openPt.moveTo(0, 0);
114 check_close(reporter, openPt);
115
116 SkPath empty;
117 check_close(reporter, empty);
118 empty.close();
119 check_close(reporter, empty);
120
121 SkPath rect;
122 rect.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
123 check_close(reporter, rect);
124 rect.close();
125 check_close(reporter, rect);
126
127 SkPath quad;
128 quad.quadTo(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
129 check_close(reporter, quad);
130 quad.close();
131 check_close(reporter, quad);
132
133 SkPath cubic;
134 quad.cubicTo(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1,
135 10*SK_Scalar1, 20 * SK_Scalar1, 20*SK_Scalar1);
136 check_close(reporter, cubic);
137 cubic.close();
138 check_close(reporter, cubic);
139
140 SkPath line;
141 line.moveTo(SK_Scalar1, SK_Scalar1);
142 line.lineTo(10 * SK_Scalar1, 10*SK_Scalar1);
143 check_close(reporter, line);
144 line.close();
145 check_close(reporter, line);
146
147 SkPath rect2;
148 rect2.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
149 rect2.close();
150 rect2.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
151 check_close(reporter, rect2);
152 rect2.close();
153 check_close(reporter, rect2);
154
155 SkPath oval3;
156 oval3.addOval(SkRect::MakeWH(SK_Scalar1*100,SK_Scalar1*100));
157 oval3.close();
158 oval3.addOval(SkRect::MakeWH(SK_Scalar1*200,SK_Scalar1*200));
159 check_close(reporter, oval3);
160 oval3.close();
161 check_close(reporter, oval3);
162
163 SkPath moves;
164 moves.moveTo(SK_Scalar1, SK_Scalar1);
165 moves.moveTo(5 * SK_Scalar1, SK_Scalar1);
166 moves.moveTo(SK_Scalar1, 10 * SK_Scalar1);
167 moves.moveTo(10 *SK_Scalar1, SK_Scalar1);
168 check_close(reporter, moves);
reed@google.com55b5f4b2011-09-07 12:23:41 +0000169
170 stroke_tiny_cubic();
bsalomon@google.comb3b8dfa2011-07-13 17:44:36 +0000171}
172
reed@google.com7c424812011-05-15 04:38:34 +0000173static void check_convexity(skiatest::Reporter* reporter, const SkPath& path,
174 SkPath::Convexity expected) {
175 SkPath::Convexity c = SkPath::ComputeConvexity(path);
176 REPORTER_ASSERT(reporter, c == expected);
177}
178
179static void test_convexity2(skiatest::Reporter* reporter) {
180 SkPath pt;
181 pt.moveTo(0, 0);
182 pt.close();
reed@google.comb54455e2011-05-16 14:16:04 +0000183 check_convexity(reporter, pt, SkPath::kConvex_Convexity);
reed@google.com7c424812011-05-15 04:38:34 +0000184
185 SkPath line;
186 line.moveTo(12, 20);
187 line.lineTo(-12, -20);
188 line.close();
reed@google.comb54455e2011-05-16 14:16:04 +0000189 check_convexity(reporter, pt, SkPath::kConvex_Convexity);
reed@google.com7c424812011-05-15 04:38:34 +0000190
191 SkPath triLeft;
192 triLeft.moveTo(0, 0);
193 triLeft.lineTo(1, 0);
194 triLeft.lineTo(1, 1);
195 triLeft.close();
196 check_convexity(reporter, triLeft, SkPath::kConvex_Convexity);
197
198 SkPath triRight;
199 triRight.moveTo(0, 0);
200 triRight.lineTo(-1, 0);
201 triRight.lineTo(1, 1);
202 triRight.close();
203 check_convexity(reporter, triRight, SkPath::kConvex_Convexity);
204
205 SkPath square;
206 square.moveTo(0, 0);
207 square.lineTo(1, 0);
208 square.lineTo(1, 1);
209 square.lineTo(0, 1);
210 square.close();
211 check_convexity(reporter, square, SkPath::kConvex_Convexity);
212
213 SkPath redundantSquare;
214 redundantSquare.moveTo(0, 0);
215 redundantSquare.lineTo(0, 0);
216 redundantSquare.lineTo(0, 0);
217 redundantSquare.lineTo(1, 0);
218 redundantSquare.lineTo(1, 0);
219 redundantSquare.lineTo(1, 0);
220 redundantSquare.lineTo(1, 1);
221 redundantSquare.lineTo(1, 1);
222 redundantSquare.lineTo(1, 1);
223 redundantSquare.lineTo(0, 1);
224 redundantSquare.lineTo(0, 1);
225 redundantSquare.lineTo(0, 1);
226 redundantSquare.close();
227 check_convexity(reporter, redundantSquare, SkPath::kConvex_Convexity);
228
229 SkPath bowTie;
230 bowTie.moveTo(0, 0);
231 bowTie.lineTo(0, 0);
232 bowTie.lineTo(0, 0);
233 bowTie.lineTo(1, 1);
234 bowTie.lineTo(1, 1);
235 bowTie.lineTo(1, 1);
236 bowTie.lineTo(1, 0);
237 bowTie.lineTo(1, 0);
238 bowTie.lineTo(1, 0);
239 bowTie.lineTo(0, 1);
240 bowTie.lineTo(0, 1);
241 bowTie.lineTo(0, 1);
242 bowTie.close();
243 check_convexity(reporter, bowTie, SkPath::kConcave_Convexity);
244
245 SkPath spiral;
246 spiral.moveTo(0, 0);
epoger@google.com2047f002011-05-17 17:36:59 +0000247 spiral.lineTo(100, 0);
248 spiral.lineTo(100, 100);
249 spiral.lineTo(0, 100);
250 spiral.lineTo(0, 50);
251 spiral.lineTo(50, 50);
252 spiral.lineTo(50, 75);
reed@google.com7c424812011-05-15 04:38:34 +0000253 spiral.close();
reed@google.com85b6e392011-05-15 20:25:17 +0000254 check_convexity(reporter, spiral, SkPath::kConcave_Convexity);
reed@google.com7c424812011-05-15 04:38:34 +0000255
256 SkPath dent;
epoger@google.com1f753992011-05-18 20:23:30 +0000257 dent.moveTo(SkIntToScalar(0), SkIntToScalar(0));
258 dent.lineTo(SkIntToScalar(100), SkIntToScalar(100));
259 dent.lineTo(SkIntToScalar(0), SkIntToScalar(100));
260 dent.lineTo(SkIntToScalar(-50), SkIntToScalar(200));
261 dent.lineTo(SkIntToScalar(-200), SkIntToScalar(100));
reed@google.com7c424812011-05-15 04:38:34 +0000262 dent.close();
263 check_convexity(reporter, dent, SkPath::kConcave_Convexity);
264}
265
reed@android.com6b82d1a2009-06-03 02:35:01 +0000266static void check_convex_bounds(skiatest::Reporter* reporter, const SkPath& p,
267 const SkRect& bounds) {
268 REPORTER_ASSERT(reporter, p.isConvex());
269 REPORTER_ASSERT(reporter, p.getBounds() == bounds);
reed@google.com62047cf2011-02-07 19:39:09 +0000270
reed@android.com6b82d1a2009-06-03 02:35:01 +0000271 SkPath p2(p);
272 REPORTER_ASSERT(reporter, p2.isConvex());
273 REPORTER_ASSERT(reporter, p2.getBounds() == bounds);
274
275 SkPath other;
276 other.swap(p2);
277 REPORTER_ASSERT(reporter, other.isConvex());
278 REPORTER_ASSERT(reporter, other.getBounds() == bounds);
279}
280
reed@google.com04863fa2011-05-15 04:08:24 +0000281static void setFromString(SkPath* path, const char str[]) {
282 bool first = true;
283 while (str) {
284 SkScalar x, y;
285 str = SkParse::FindScalar(str, &x);
286 if (NULL == str) {
287 break;
288 }
289 str = SkParse::FindScalar(str, &y);
290 SkASSERT(str);
291 if (first) {
292 path->moveTo(x, y);
293 first = false;
294 } else {
295 path->lineTo(x, y);
296 }
297 }
298}
299
300static void test_convexity(skiatest::Reporter* reporter) {
reed@google.com04863fa2011-05-15 04:08:24 +0000301 static const SkPath::Convexity C = SkPath::kConcave_Convexity;
302 static const SkPath::Convexity V = SkPath::kConvex_Convexity;
303
304 SkPath path;
305
reed@google.comb54455e2011-05-16 14:16:04 +0000306 REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
reed@google.com04863fa2011-05-15 04:08:24 +0000307 path.addCircle(0, 0, 10);
308 REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
309 path.addCircle(0, 0, 10); // 2nd circle
310 REPORTER_ASSERT(reporter, C == SkPath::ComputeConvexity(path));
311 path.reset();
312 path.addRect(0, 0, 10, 10, SkPath::kCCW_Direction);
313 REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
314 path.reset();
315 path.addRect(0, 0, 10, 10, SkPath::kCW_Direction);
316 REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
317
318 static const struct {
319 const char* fPathStr;
320 SkPath::Convexity fExpectedConvexity;
321 } gRec[] = {
reed@google.comb54455e2011-05-16 14:16:04 +0000322 { "", SkPath::kConvex_Convexity },
323 { "0 0", SkPath::kConvex_Convexity },
324 { "0 0 10 10", SkPath::kConvex_Convexity },
reed@google.com85b6e392011-05-15 20:25:17 +0000325 { "0 0 10 10 20 20 0 0 10 10", SkPath::kConcave_Convexity },
reed@google.com04863fa2011-05-15 04:08:24 +0000326 { "0 0 10 10 10 20", SkPath::kConvex_Convexity },
327 { "0 0 10 10 10 0", SkPath::kConvex_Convexity },
328 { "0 0 10 10 10 0 0 10", SkPath::kConcave_Convexity },
329 { "0 0 10 0 0 10 -10 -10", SkPath::kConcave_Convexity },
330 };
331
332 for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
333 SkPath path;
334 setFromString(&path, gRec[i].fPathStr);
335 SkPath::Convexity c = SkPath::ComputeConvexity(path);
336 REPORTER_ASSERT(reporter, c == gRec[i].fExpectedConvexity);
337 }
338}
339
caryclark@google.comf1316942011-07-26 19:54:45 +0000340// Simple isRect test is inline TestPath, below.
341// test_isRect provides more extensive testing.
342static void test_isRect(skiatest::Reporter* reporter) {
343 // passing tests (all moveTo / lineTo...
344 SkPoint r1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
345 SkPoint r2[] = {{1, 0}, {1, 1}, {0, 1}, {0, 0}};
346 SkPoint r3[] = {{1, 1}, {0, 1}, {0, 0}, {1, 0}};
347 SkPoint r4[] = {{0, 1}, {0, 0}, {1, 0}, {1, 1}};
348 SkPoint r5[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}};
349 SkPoint r6[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
350 SkPoint r7[] = {{1, 1}, {1, 0}, {0, 0}, {0, 1}};
351 SkPoint r8[] = {{1, 0}, {0, 0}, {0, 1}, {1, 1}};
352 SkPoint r9[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
353 SkPoint ra[] = {{0, 0}, {0, .5f}, {0, 1}, {.5f, 1}, {1, 1}, {1, .5f},
354 {1, 0}, {.5f, 0}};
355 SkPoint rb[] = {{0, 0}, {.5f, 0}, {1, 0}, {1, .5f}, {1, 1}, {.5f, 1},
356 {0, 1}, {0, .5f}};
357 SkPoint rc[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}};
358 SkPoint rd[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}};
359 SkPoint re[] = {{0, 0}, {1, 0}, {1, 0}, {1, 1}, {0, 1}};
360
361 // failing tests
362 SkPoint f1[] = {{0, 0}, {1, 0}, {1, 1}}; // too few points
363 SkPoint f2[] = {{0, 0}, {1, 1}, {0, 1}, {1, 0}}; // diagonal
364 SkPoint f3[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}, {1, 0}}; // wraps
365 SkPoint f4[] = {{0, 0}, {1, 0}, {0, 0}, {1, 0}, {1, 1}, {0, 1}}; // backs up
366 SkPoint f5[] = {{0, 0}, {1, 0}, {1, 1}, {2, 0}}; // end overshoots
367 SkPoint f6[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 2}}; // end overshoots
368 SkPoint f7[] = {{0, 0}, {1, 0}, {1, 1}, {0, 2}}; // end overshoots
369 SkPoint f8[] = {{0, 0}, {1, 0}, {1, 1}, {1, 0}}; // 'L'
370
371 // failing, no close
372 SkPoint c1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}}; // close doesn't match
373 SkPoint c2[] = {{0, 0}, {1, 0}, {1, 2}, {0, 2}, {0, 1}}; // ditto
374
375 size_t testLen[] = {
376 sizeof(r1), sizeof(r2), sizeof(r3), sizeof(r4), sizeof(r5), sizeof(r6),
377 sizeof(r7), sizeof(r8), sizeof(r9), sizeof(ra), sizeof(rb), sizeof(rc),
378 sizeof(rd), sizeof(re),
379 sizeof(f1), sizeof(f2), sizeof(f3), sizeof(f4), sizeof(f5), sizeof(f6),
380 sizeof(f7), sizeof(f8),
381 sizeof(c1), sizeof(c2)
382 };
383 SkPoint* tests[] = {
384 r1, r2, r3, r4, r5, r6, r7, r8, r9, ra, rb, rc, rd, re,
385 f1, f2, f3, f4, f5, f6, f7, f8,
386 c1, c2
387 };
388 SkPoint* lastPass = re;
389 SkPoint* lastClose = f8;
390 bool fail = false;
391 bool close = true;
392 const size_t testCount = sizeof(tests) / sizeof(tests[0]);
393 size_t index;
394 for (size_t testIndex = 0; testIndex < testCount; ++testIndex) {
395 SkPath path;
396 path.moveTo(tests[testIndex][0].fX, tests[testIndex][0].fY);
397 for (index = 1; index < testLen[testIndex] / sizeof(SkPoint); ++index) {
398 path.lineTo(tests[testIndex][index].fX, tests[testIndex][index].fY);
399 }
400 if (close) {
401 path.close();
402 }
403 REPORTER_ASSERT(reporter, fail ^ path.isRect(0));
404 if (tests[testIndex] == lastPass) {
405 fail = true;
406 }
407 if (tests[testIndex] == lastClose) {
408 close = false;
409 }
410 }
411
412 // fail, close then line
413 SkPath path1;
414 path1.moveTo(r1[0].fX, r1[0].fY);
415 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
416 path1.lineTo(r1[index].fX, r1[index].fY);
417 }
418 path1.close();
419 path1.lineTo(1, 0);
420 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
421
422 // fail, move in the middle
423 path1.reset();
424 path1.moveTo(r1[0].fX, r1[0].fY);
425 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
426 if (index == 2) {
427 path1.moveTo(1, .5f);
428 }
429 path1.lineTo(r1[index].fX, r1[index].fY);
430 }
431 path1.close();
432 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
433
434 // fail, move on the edge
435 path1.reset();
436 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
437 path1.moveTo(r1[index - 1].fX, r1[index - 1].fY);
438 path1.lineTo(r1[index].fX, r1[index].fY);
439 }
440 path1.close();
441 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
442
443 // fail, quad
444 path1.reset();
445 path1.moveTo(r1[0].fX, r1[0].fY);
446 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
447 if (index == 2) {
448 path1.quadTo(1, .5f, 1, .5f);
449 }
450 path1.lineTo(r1[index].fX, r1[index].fY);
451 }
452 path1.close();
453 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
454
455 // fail, cubic
456 path1.reset();
457 path1.moveTo(r1[0].fX, r1[0].fY);
458 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
459 if (index == 2) {
460 path1.cubicTo(1, .5f, 1, .5f, 1, .5f);
461 }
462 path1.lineTo(r1[index].fX, r1[index].fY);
463 }
464 path1.close();
465 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
466}
467
reed@google.com53effc52011-09-21 19:05:12 +0000468static void test_flattening(skiatest::Reporter* reporter) {
469 SkPath p;
470
471 static const SkPoint pts[] = {
472 { 0, 0 },
473 { SkIntToScalar(10), SkIntToScalar(10) },
474 { SkIntToScalar(20), SkIntToScalar(10) }, { SkIntToScalar(20), 0 },
475 { 0, 0 }, { 0, SkIntToScalar(10) }, { SkIntToScalar(1), SkIntToScalar(10) }
476 };
477 p.moveTo(pts[0]);
478 p.lineTo(pts[1]);
479 p.quadTo(pts[2], pts[3]);
480 p.cubicTo(pts[4], pts[5], pts[6]);
481
482 SkWriter32 writer(100);
483 p.flatten(writer);
484 size_t size = writer.size();
485 SkAutoMalloc storage(size);
486 writer.flatten(storage.get());
487 SkReader32 reader(storage.get(), size);
488
489 SkPath p1;
490 REPORTER_ASSERT(reporter, p1 != p);
491 p1.unflatten(reader);
492 REPORTER_ASSERT(reporter, p1 == p);
493}
494
495static void test_transform(skiatest::Reporter* reporter) {
496 SkPath p, p1;
497
498 static const SkPoint pts[] = {
499 { 0, 0 },
500 { SkIntToScalar(10), SkIntToScalar(10) },
501 { SkIntToScalar(20), SkIntToScalar(10) }, { SkIntToScalar(20), 0 },
502 { 0, 0 }, { 0, SkIntToScalar(10) }, { SkIntToScalar(1), SkIntToScalar(10) }
503 };
504 p.moveTo(pts[0]);
505 p.lineTo(pts[1]);
506 p.quadTo(pts[2], pts[3]);
507 p.cubicTo(pts[4], pts[5], pts[6]);
508
509 SkMatrix matrix;
510 matrix.reset();
511 p.transform(matrix, &p1);
512 REPORTER_ASSERT(reporter, p == p1);
513
514 matrix.setScale(SK_Scalar1 * 2, SK_Scalar1 * 3);
515 p.transform(matrix, &p1);
516 SkPoint pts1[7];
517 int count = p1.getPoints(pts1, 7);
518 REPORTER_ASSERT(reporter, 7 == count);
519 for (int i = 0; i < count; ++i) {
520 SkPoint newPt = SkPoint::Make(pts[i].fX * 2, pts[i].fY * 3);
521 REPORTER_ASSERT(reporter, newPt == pts1[i]);
522 }
523}
524
reed@google.com10296cc2011-09-21 12:29:05 +0000525#define kCurveSegmentMask (SkPath::kQuad_SegmentMask | SkPath::kCubic_SegmentMask)
526
reed@google.com04863fa2011-05-15 04:08:24 +0000527void TestPath(skiatest::Reporter* reporter);
528void TestPath(skiatest::Reporter* reporter) {
reed@android.com60bc6d52010-02-11 11:09:39 +0000529 {
530 SkSize size;
531 size.fWidth = 3.4f;
532 size.width();
533 size = SkSize::Make(3,4);
534 SkISize isize = SkISize::Make(3,4);
535 }
536
537 SkTSize<SkScalar>::Make(3,4);
538
reed@android.com3abec1d2009-03-02 05:36:20 +0000539 SkPath p, p2;
540 SkRect bounds, bounds2;
reed@android.com80e39a72009-04-02 16:59:40 +0000541
reed@android.com3abec1d2009-03-02 05:36:20 +0000542 REPORTER_ASSERT(reporter, p.isEmpty());
reed@google.com10296cc2011-09-21 12:29:05 +0000543 REPORTER_ASSERT(reporter, 0 == p.getSegmentMasks());
reed@google.comb54455e2011-05-16 14:16:04 +0000544 REPORTER_ASSERT(reporter, p.isConvex());
reed@android.com3abec1d2009-03-02 05:36:20 +0000545 REPORTER_ASSERT(reporter, p.getFillType() == SkPath::kWinding_FillType);
546 REPORTER_ASSERT(reporter, !p.isInverseFillType());
547 REPORTER_ASSERT(reporter, p == p2);
548 REPORTER_ASSERT(reporter, !(p != p2));
549
reed@android.comd252db02009-04-01 18:31:44 +0000550 REPORTER_ASSERT(reporter, p.getBounds().isEmpty());
reed@android.com80e39a72009-04-02 16:59:40 +0000551
reed@android.com3abec1d2009-03-02 05:36:20 +0000552 bounds.set(0, 0, SK_Scalar1, SK_Scalar1);
reed@android.com6b82d1a2009-06-03 02:35:01 +0000553
reed@android.com6b82d1a2009-06-03 02:35:01 +0000554 p.addRoundRect(bounds, SK_Scalar1, SK_Scalar1);
555 check_convex_bounds(reporter, p, bounds);
reed@google.com10296cc2011-09-21 12:29:05 +0000556 // we have quads or cubics
557 REPORTER_ASSERT(reporter, p.getSegmentMasks() & kCurveSegmentMask);
reed@google.com62047cf2011-02-07 19:39:09 +0000558
reed@android.com6b82d1a2009-06-03 02:35:01 +0000559 p.reset();
reed@google.com10296cc2011-09-21 12:29:05 +0000560 REPORTER_ASSERT(reporter, 0 == p.getSegmentMasks());
561
reed@android.com6b82d1a2009-06-03 02:35:01 +0000562 p.addOval(bounds);
563 check_convex_bounds(reporter, p, bounds);
reed@google.com62047cf2011-02-07 19:39:09 +0000564
reed@android.com6b82d1a2009-06-03 02:35:01 +0000565 p.reset();
reed@android.com3abec1d2009-03-02 05:36:20 +0000566 p.addRect(bounds);
reed@android.com6b82d1a2009-06-03 02:35:01 +0000567 check_convex_bounds(reporter, p, bounds);
reed@google.com10296cc2011-09-21 12:29:05 +0000568 // we have only lines
569 REPORTER_ASSERT(reporter, SkPath::kLine_SegmentMask == p.getSegmentMasks());
reed@android.com3abec1d2009-03-02 05:36:20 +0000570
571 REPORTER_ASSERT(reporter, p != p2);
572 REPORTER_ASSERT(reporter, !(p == p2));
573
574 // does getPoints return the right result
575 REPORTER_ASSERT(reporter, p.getPoints(NULL, 5) == 4);
576 SkPoint pts[4];
577 int count = p.getPoints(pts, 4);
578 REPORTER_ASSERT(reporter, count == 4);
579 bounds2.set(pts, 4);
580 REPORTER_ASSERT(reporter, bounds == bounds2);
reed@android.com80e39a72009-04-02 16:59:40 +0000581
reed@android.com3abec1d2009-03-02 05:36:20 +0000582 bounds.offset(SK_Scalar1*3, SK_Scalar1*4);
583 p.offset(SK_Scalar1*3, SK_Scalar1*4);
reed@android.comd252db02009-04-01 18:31:44 +0000584 REPORTER_ASSERT(reporter, bounds == p.getBounds());
reed@android.com3abec1d2009-03-02 05:36:20 +0000585
reed@android.com3abec1d2009-03-02 05:36:20 +0000586 REPORTER_ASSERT(reporter, p.isRect(NULL));
caryclark@google.comf1316942011-07-26 19:54:45 +0000587 bounds2.setEmpty();
reed@android.com3abec1d2009-03-02 05:36:20 +0000588 REPORTER_ASSERT(reporter, p.isRect(&bounds2));
589 REPORTER_ASSERT(reporter, bounds == bounds2);
reed@android.com80e39a72009-04-02 16:59:40 +0000590
reed@android.com3abec1d2009-03-02 05:36:20 +0000591 // now force p to not be a rect
592 bounds.set(0, 0, SK_Scalar1/2, SK_Scalar1/2);
593 p.addRect(bounds);
594 REPORTER_ASSERT(reporter, !p.isRect(NULL));
caryclark@google.comf1316942011-07-26 19:54:45 +0000595 test_isRect(reporter);
reed@android.com3abec1d2009-03-02 05:36:20 +0000596
597 SkPoint pt;
598
599 p.moveTo(SK_Scalar1, 0);
600 p.getLastPt(&pt);
601 REPORTER_ASSERT(reporter, pt.fX == SK_Scalar1);
reed@google.com62047cf2011-02-07 19:39:09 +0000602
reed@google.com04863fa2011-05-15 04:08:24 +0000603 test_convexity(reporter);
reed@google.com7c424812011-05-15 04:38:34 +0000604 test_convexity2(reporter);
bsalomon@google.comb3b8dfa2011-07-13 17:44:36 +0000605 test_close(reporter);
reed@google.com10296cc2011-09-21 12:29:05 +0000606
607 p.reset();
608 p.moveTo(0, 0);
609 p.quadTo(100, 100, 200, 200);
610 REPORTER_ASSERT(reporter, SkPath::kQuad_SegmentMask == p.getSegmentMasks());
611 p.cubicTo(100, 100, 200, 200, 300, 300);
612 REPORTER_ASSERT(reporter, kCurveSegmentMask == p.getSegmentMasks());
613 p.reset();
614 p.moveTo(0, 0);
615 p.cubicTo(100, 100, 200, 200, 300, 300);
616 REPORTER_ASSERT(reporter, SkPath::kCubic_SegmentMask == p.getSegmentMasks());
reed@google.com53effc52011-09-21 19:05:12 +0000617
618 test_flattening(reporter);
619 test_transform(reporter);
reed@google.com3563c9e2011-11-14 19:34:57 +0000620 test_bounds(reporter);
reed@android.com3abec1d2009-03-02 05:36:20 +0000621}
622
623#include "TestClassDef.h"
624DEFINE_TESTCLASS("Path", PathTestClass, TestPath)