blob: ff4db0b632b0ec6169a2e0e263d707dd5805db43 [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
bsalomon@google.comf0ed80a2012-02-17 13:38:26 +000018/**
19 * cheapIsDirection can take a shortcut when a path is marked convex.
20 * This function ensures that we always test cheapIsDirection when the path
21 * is flagged with unknown convexity status.
22 */
23static void check_direction(SkPath* path,
24 SkPath::Direction expectedDir,
25 skiatest::Reporter* reporter) {
26 if (SkPath::kConvex_Convexity == path->getConvexity()) {
27 REPORTER_ASSERT(reporter, path->cheapIsDirection(expectedDir));
28 path->setConvexity(SkPath::kUnknown_Convexity);
29 }
30 REPORTER_ASSERT(reporter, path->cheapIsDirection(expectedDir));
31}
32
reed@google.com3e71a882012-01-10 18:44:37 +000033static void test_direction(skiatest::Reporter* reporter) {
34 size_t i;
35 SkPath path;
36 REPORTER_ASSERT(reporter, !path.cheapComputeDirection(NULL));
37 REPORTER_ASSERT(reporter, !path.cheapIsDirection(SkPath::kCW_Direction));
38 REPORTER_ASSERT(reporter, !path.cheapIsDirection(SkPath::kCCW_Direction));
39
40 static const char* gDegen[] = {
41 "M 10 10",
42 "M 10 10 M 20 20",
43 "M 10 10 L 20 20",
44 "M 10 10 L 10 10 L 10 10",
45 "M 10 10 Q 10 10 10 10",
46 "M 10 10 C 10 10 10 10 10 10",
47 };
48 for (i = 0; i < SK_ARRAY_COUNT(gDegen); ++i) {
49 path.reset();
50 bool valid = SkParsePath::FromSVGString(gDegen[i], &path);
51 REPORTER_ASSERT(reporter, valid);
52 REPORTER_ASSERT(reporter, !path.cheapComputeDirection(NULL));
53 }
54
55 static const char* gCW[] = {
reed@google.comcabaf1d2012-01-11 21:03:05 +000056 "M 10 10 L 10 10 Q 20 10 20 20",
reed@google.com3e71a882012-01-10 18:44:37 +000057 "M 10 10 C 20 10 20 20 20 20",
reed@google.comd4146662012-01-31 15:42:29 +000058 "M 20 10 Q 20 20 30 20 L 10 20", // test double-back at y-max
reed@google.com3e71a882012-01-10 18:44:37 +000059 };
60 for (i = 0; i < SK_ARRAY_COUNT(gCW); ++i) {
61 path.reset();
62 bool valid = SkParsePath::FromSVGString(gCW[i], &path);
63 REPORTER_ASSERT(reporter, valid);
bsalomon@google.comf0ed80a2012-02-17 13:38:26 +000064 check_direction(&path, SkPath::kCW_Direction, reporter);
reed@google.com3e71a882012-01-10 18:44:37 +000065 }
66
67 static const char* gCCW[] = {
reed@google.comcabaf1d2012-01-11 21:03:05 +000068 "M 10 10 L 10 10 Q 20 10 20 -20",
reed@google.com3e71a882012-01-10 18:44:37 +000069 "M 10 10 C 20 10 20 -20 20 -20",
reed@google.comd4146662012-01-31 15:42:29 +000070 "M 20 10 Q 20 20 10 20 L 30 20", // test double-back at y-max
reed@google.com3e71a882012-01-10 18:44:37 +000071 };
72 for (i = 0; i < SK_ARRAY_COUNT(gCCW); ++i) {
73 path.reset();
74 bool valid = SkParsePath::FromSVGString(gCCW[i], &path);
75 REPORTER_ASSERT(reporter, valid);
bsalomon@google.comf0ed80a2012-02-17 13:38:26 +000076 check_direction(&path, SkPath::kCCW_Direction, reporter);
reed@google.com3e71a882012-01-10 18:44:37 +000077 }
reed@google.comac8543f2012-01-30 20:51:25 +000078
79 // Test two donuts, each wound a different direction. Only the outer contour
80 // determines the cheap direction
81 path.reset();
82 path.addCircle(0, 0, SkIntToScalar(2), SkPath::kCW_Direction);
83 path.addCircle(0, 0, SkIntToScalar(1), SkPath::kCCW_Direction);
bsalomon@google.comf0ed80a2012-02-17 13:38:26 +000084 check_direction(&path, SkPath::kCW_Direction, reporter);
85
reed@google.comac8543f2012-01-30 20:51:25 +000086 path.reset();
87 path.addCircle(0, 0, SkIntToScalar(1), SkPath::kCW_Direction);
88 path.addCircle(0, 0, SkIntToScalar(2), SkPath::kCCW_Direction);
bsalomon@google.comf0ed80a2012-02-17 13:38:26 +000089 check_direction(&path, SkPath::kCCW_Direction, reporter);
90
bsalomon@google.com6843ac42012-02-17 13:49:03 +000091#ifdef SK_SCALAR_IS_FLOAT
bsalomon@google.comf0ed80a2012-02-17 13:38:26 +000092 // triangle with one point really far from the origin.
93 path.reset();
94 // the first point is roughly 1.05e10, 1.05e10
bsalomon@google.com53aab782012-02-23 14:54:49 +000095 path.moveTo(SkFloatToScalar(SkBits2Float(0x501c7652)), SkFloatToScalar(SkBits2Float(0x501c7652)));
96 path.lineTo(110 * SK_Scalar1, -10 * SK_Scalar1);
97 path.lineTo(-10 * SK_Scalar1, 60 * SK_Scalar1);
98 check_direction(&path, SkPath::kCCW_Direction, reporter);
99#endif
reed@google.com3e71a882012-01-10 18:44:37 +0000100}
101
reed@google.comffdb0182011-11-14 19:29:14 +0000102static void add_rect(SkPath* path, const SkRect& r) {
103 path->moveTo(r.fLeft, r.fTop);
104 path->lineTo(r.fRight, r.fTop);
105 path->lineTo(r.fRight, r.fBottom);
106 path->lineTo(r.fLeft, r.fBottom);
107 path->close();
108}
109
110static void test_bounds(skiatest::Reporter* reporter) {
111 static const SkRect rects[] = {
reed@google.com3563c9e2011-11-14 19:34:57 +0000112 { SkIntToScalar(10), SkIntToScalar(160), SkIntToScalar(610), SkIntToScalar(160) },
113 { SkIntToScalar(610), SkIntToScalar(160), SkIntToScalar(610), SkIntToScalar(199) },
114 { SkIntToScalar(10), SkIntToScalar(198), SkIntToScalar(610), SkIntToScalar(199) },
115 { SkIntToScalar(10), SkIntToScalar(160), SkIntToScalar(10), SkIntToScalar(199) },
reed@google.comffdb0182011-11-14 19:29:14 +0000116 };
117
118 SkPath path0, path1;
119 for (size_t i = 0; i < SK_ARRAY_COUNT(rects); ++i) {
120 path0.addRect(rects[i]);
121 add_rect(&path1, rects[i]);
122 }
123
124 REPORTER_ASSERT(reporter, path0.getBounds() == path1.getBounds());
125}
126
reed@google.com55b5f4b2011-09-07 12:23:41 +0000127static void stroke_cubic(const SkPoint pts[4]) {
128 SkPath path;
129 path.moveTo(pts[0]);
130 path.cubicTo(pts[1], pts[2], pts[3]);
131
132 SkPaint paint;
133 paint.setStyle(SkPaint::kStroke_Style);
134 paint.setStrokeWidth(SK_Scalar1 * 2);
135
136 SkPath fill;
137 paint.getFillPath(path, &fill);
138}
139
140// just ensure this can run w/o any SkASSERTS firing in the debug build
141// we used to assert due to differences in how we determine a degenerate vector
142// but that was fixed with the introduction of SkPoint::CanNormalize
143static void stroke_tiny_cubic() {
144 SkPoint p0[] = {
145 { 372.0f, 92.0f },
146 { 372.0f, 92.0f },
147 { 372.0f, 92.0f },
148 { 372.0f, 92.0f },
149 };
150
151 stroke_cubic(p0);
152
153 SkPoint p1[] = {
154 { 372.0f, 92.0f },
155 { 372.0007f, 92.000755f },
156 { 371.99927f, 92.003922f },
157 { 371.99826f, 92.003899f },
158 };
159
160 stroke_cubic(p1);
161}
162
bsalomon@google.comb3b8dfa2011-07-13 17:44:36 +0000163static void check_close(skiatest::Reporter* reporter, const SkPath& path) {
164 for (int i = 0; i < 2; ++i) {
robertphillips@google.com09042b82012-04-06 20:01:46 +0000165 SkPath::Iter iter(path, SkToBool(i));
bsalomon@google.comb3b8dfa2011-07-13 17:44:36 +0000166 SkPoint mv;
167 SkPoint pts[4];
168 SkPath::Verb v;
169 int nMT = 0;
170 int nCL = 0;
tomhudson@google.com221db3c2011-07-28 21:10:29 +0000171 mv.set(0, 0);
bsalomon@google.comb3b8dfa2011-07-13 17:44:36 +0000172 while (SkPath::kDone_Verb != (v = iter.next(pts))) {
173 switch (v) {
174 case SkPath::kMove_Verb:
175 mv = pts[0];
176 ++nMT;
177 break;
178 case SkPath::kClose_Verb:
179 REPORTER_ASSERT(reporter, mv == pts[0]);
180 ++nCL;
181 break;
182 default:
183 break;
184 }
185 }
186 // if we force a close on the interator we should have a close
187 // for every moveTo
188 REPORTER_ASSERT(reporter, !i || nMT == nCL);
189 }
190}
191
192static void test_close(skiatest::Reporter* reporter) {
193 SkPath closePt;
194 closePt.moveTo(0, 0);
195 closePt.close();
196 check_close(reporter, closePt);
197
198 SkPath openPt;
199 openPt.moveTo(0, 0);
200 check_close(reporter, openPt);
201
202 SkPath empty;
203 check_close(reporter, empty);
204 empty.close();
205 check_close(reporter, empty);
206
207 SkPath rect;
208 rect.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
209 check_close(reporter, rect);
210 rect.close();
211 check_close(reporter, rect);
212
213 SkPath quad;
214 quad.quadTo(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
215 check_close(reporter, quad);
216 quad.close();
217 check_close(reporter, quad);
218
219 SkPath cubic;
220 quad.cubicTo(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1,
221 10*SK_Scalar1, 20 * SK_Scalar1, 20*SK_Scalar1);
222 check_close(reporter, cubic);
223 cubic.close();
224 check_close(reporter, cubic);
225
226 SkPath line;
227 line.moveTo(SK_Scalar1, SK_Scalar1);
228 line.lineTo(10 * SK_Scalar1, 10*SK_Scalar1);
229 check_close(reporter, line);
230 line.close();
231 check_close(reporter, line);
232
233 SkPath rect2;
234 rect2.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
235 rect2.close();
236 rect2.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
237 check_close(reporter, rect2);
238 rect2.close();
239 check_close(reporter, rect2);
240
241 SkPath oval3;
242 oval3.addOval(SkRect::MakeWH(SK_Scalar1*100,SK_Scalar1*100));
243 oval3.close();
244 oval3.addOval(SkRect::MakeWH(SK_Scalar1*200,SK_Scalar1*200));
245 check_close(reporter, oval3);
246 oval3.close();
247 check_close(reporter, oval3);
248
249 SkPath moves;
250 moves.moveTo(SK_Scalar1, SK_Scalar1);
251 moves.moveTo(5 * SK_Scalar1, SK_Scalar1);
252 moves.moveTo(SK_Scalar1, 10 * SK_Scalar1);
253 moves.moveTo(10 *SK_Scalar1, SK_Scalar1);
254 check_close(reporter, moves);
reed@google.com55b5f4b2011-09-07 12:23:41 +0000255
256 stroke_tiny_cubic();
bsalomon@google.comb3b8dfa2011-07-13 17:44:36 +0000257}
258
reed@google.com7c424812011-05-15 04:38:34 +0000259static void check_convexity(skiatest::Reporter* reporter, const SkPath& path,
260 SkPath::Convexity expected) {
261 SkPath::Convexity c = SkPath::ComputeConvexity(path);
262 REPORTER_ASSERT(reporter, c == expected);
263}
264
265static void test_convexity2(skiatest::Reporter* reporter) {
266 SkPath pt;
267 pt.moveTo(0, 0);
268 pt.close();
reed@google.comb54455e2011-05-16 14:16:04 +0000269 check_convexity(reporter, pt, SkPath::kConvex_Convexity);
reed@google.com7c424812011-05-15 04:38:34 +0000270
271 SkPath line;
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000272 line.moveTo(12*SK_Scalar1, 20*SK_Scalar1);
273 line.lineTo(-12*SK_Scalar1, -20*SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000274 line.close();
reed@google.comb54455e2011-05-16 14:16:04 +0000275 check_convexity(reporter, pt, SkPath::kConvex_Convexity);
reed@google.com7c424812011-05-15 04:38:34 +0000276
277 SkPath triLeft;
278 triLeft.moveTo(0, 0);
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000279 triLeft.lineTo(SK_Scalar1, 0);
280 triLeft.lineTo(SK_Scalar1, SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000281 triLeft.close();
282 check_convexity(reporter, triLeft, SkPath::kConvex_Convexity);
283
284 SkPath triRight;
285 triRight.moveTo(0, 0);
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000286 triRight.lineTo(-SK_Scalar1, 0);
287 triRight.lineTo(SK_Scalar1, SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000288 triRight.close();
289 check_convexity(reporter, triRight, SkPath::kConvex_Convexity);
290
291 SkPath square;
292 square.moveTo(0, 0);
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000293 square.lineTo(SK_Scalar1, 0);
294 square.lineTo(SK_Scalar1, SK_Scalar1);
295 square.lineTo(0, SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000296 square.close();
297 check_convexity(reporter, square, SkPath::kConvex_Convexity);
298
299 SkPath redundantSquare;
300 redundantSquare.moveTo(0, 0);
301 redundantSquare.lineTo(0, 0);
302 redundantSquare.lineTo(0, 0);
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000303 redundantSquare.lineTo(SK_Scalar1, 0);
304 redundantSquare.lineTo(SK_Scalar1, 0);
305 redundantSquare.lineTo(SK_Scalar1, 0);
306 redundantSquare.lineTo(SK_Scalar1, SK_Scalar1);
307 redundantSquare.lineTo(SK_Scalar1, SK_Scalar1);
308 redundantSquare.lineTo(SK_Scalar1, SK_Scalar1);
309 redundantSquare.lineTo(0, SK_Scalar1);
310 redundantSquare.lineTo(0, SK_Scalar1);
311 redundantSquare.lineTo(0, SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000312 redundantSquare.close();
313 check_convexity(reporter, redundantSquare, SkPath::kConvex_Convexity);
314
315 SkPath bowTie;
316 bowTie.moveTo(0, 0);
317 bowTie.lineTo(0, 0);
318 bowTie.lineTo(0, 0);
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000319 bowTie.lineTo(SK_Scalar1, SK_Scalar1);
320 bowTie.lineTo(SK_Scalar1, SK_Scalar1);
321 bowTie.lineTo(SK_Scalar1, SK_Scalar1);
322 bowTie.lineTo(SK_Scalar1, 0);
323 bowTie.lineTo(SK_Scalar1, 0);
324 bowTie.lineTo(SK_Scalar1, 0);
325 bowTie.lineTo(0, SK_Scalar1);
326 bowTie.lineTo(0, SK_Scalar1);
327 bowTie.lineTo(0, SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000328 bowTie.close();
329 check_convexity(reporter, bowTie, SkPath::kConcave_Convexity);
330
331 SkPath spiral;
332 spiral.moveTo(0, 0);
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000333 spiral.lineTo(100*SK_Scalar1, 0);
334 spiral.lineTo(100*SK_Scalar1, 100*SK_Scalar1);
335 spiral.lineTo(0, 100*SK_Scalar1);
336 spiral.lineTo(0, 50*SK_Scalar1);
337 spiral.lineTo(50*SK_Scalar1, 50*SK_Scalar1);
338 spiral.lineTo(50*SK_Scalar1, 75*SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000339 spiral.close();
reed@google.com85b6e392011-05-15 20:25:17 +0000340 check_convexity(reporter, spiral, SkPath::kConcave_Convexity);
reed@google.com7c424812011-05-15 04:38:34 +0000341
342 SkPath dent;
schenney@chromium.org6c31d9d2011-12-20 16:33:30 +0000343 dent.moveTo(0, 0);
344 dent.lineTo(100*SK_Scalar1, 100*SK_Scalar1);
345 dent.lineTo(0, 100*SK_Scalar1);
346 dent.lineTo(-50*SK_Scalar1, 200*SK_Scalar1);
347 dent.lineTo(-200*SK_Scalar1, 100*SK_Scalar1);
reed@google.com7c424812011-05-15 04:38:34 +0000348 dent.close();
349 check_convexity(reporter, dent, SkPath::kConcave_Convexity);
350}
351
reed@android.com6b82d1a2009-06-03 02:35:01 +0000352static void check_convex_bounds(skiatest::Reporter* reporter, const SkPath& p,
353 const SkRect& bounds) {
354 REPORTER_ASSERT(reporter, p.isConvex());
355 REPORTER_ASSERT(reporter, p.getBounds() == bounds);
reed@google.com62047cf2011-02-07 19:39:09 +0000356
reed@android.com6b82d1a2009-06-03 02:35:01 +0000357 SkPath p2(p);
358 REPORTER_ASSERT(reporter, p2.isConvex());
359 REPORTER_ASSERT(reporter, p2.getBounds() == bounds);
360
361 SkPath other;
362 other.swap(p2);
363 REPORTER_ASSERT(reporter, other.isConvex());
364 REPORTER_ASSERT(reporter, other.getBounds() == bounds);
365}
366
reed@google.com04863fa2011-05-15 04:08:24 +0000367static void setFromString(SkPath* path, const char str[]) {
368 bool first = true;
369 while (str) {
370 SkScalar x, y;
371 str = SkParse::FindScalar(str, &x);
372 if (NULL == str) {
373 break;
374 }
375 str = SkParse::FindScalar(str, &y);
376 SkASSERT(str);
377 if (first) {
378 path->moveTo(x, y);
379 first = false;
380 } else {
381 path->lineTo(x, y);
382 }
383 }
384}
385
386static void test_convexity(skiatest::Reporter* reporter) {
reed@google.com04863fa2011-05-15 04:08:24 +0000387 static const SkPath::Convexity C = SkPath::kConcave_Convexity;
388 static const SkPath::Convexity V = SkPath::kConvex_Convexity;
389
390 SkPath path;
391
reed@google.comb54455e2011-05-16 14:16:04 +0000392 REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
reed@google.come3543972012-01-10 18:59:22 +0000393 path.addCircle(0, 0, SkIntToScalar(10));
reed@google.com04863fa2011-05-15 04:08:24 +0000394 REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
reed@google.come3543972012-01-10 18:59:22 +0000395 path.addCircle(0, 0, SkIntToScalar(10)); // 2nd circle
reed@google.com04863fa2011-05-15 04:08:24 +0000396 REPORTER_ASSERT(reporter, C == SkPath::ComputeConvexity(path));
397 path.reset();
reed@google.come3543972012-01-10 18:59:22 +0000398 path.addRect(0, 0, SkIntToScalar(10), SkIntToScalar(10), SkPath::kCCW_Direction);
reed@google.com04863fa2011-05-15 04:08:24 +0000399 REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
reed@google.com3e71a882012-01-10 18:44:37 +0000400 REPORTER_ASSERT(reporter, path.cheapIsDirection(SkPath::kCCW_Direction));
reed@google.com04863fa2011-05-15 04:08:24 +0000401 path.reset();
reed@google.come3543972012-01-10 18:59:22 +0000402 path.addRect(0, 0, SkIntToScalar(10), SkIntToScalar(10), SkPath::kCW_Direction);
reed@google.com04863fa2011-05-15 04:08:24 +0000403 REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
reed@google.com3e71a882012-01-10 18:44:37 +0000404 REPORTER_ASSERT(reporter, path.cheapIsDirection(SkPath::kCW_Direction));
reed@google.com04863fa2011-05-15 04:08:24 +0000405
406 static const struct {
407 const char* fPathStr;
408 SkPath::Convexity fExpectedConvexity;
409 } gRec[] = {
reed@google.comb54455e2011-05-16 14:16:04 +0000410 { "", SkPath::kConvex_Convexity },
411 { "0 0", SkPath::kConvex_Convexity },
412 { "0 0 10 10", SkPath::kConvex_Convexity },
reed@google.com85b6e392011-05-15 20:25:17 +0000413 { "0 0 10 10 20 20 0 0 10 10", SkPath::kConcave_Convexity },
reed@google.com04863fa2011-05-15 04:08:24 +0000414 { "0 0 10 10 10 20", SkPath::kConvex_Convexity },
415 { "0 0 10 10 10 0", SkPath::kConvex_Convexity },
416 { "0 0 10 10 10 0 0 10", SkPath::kConcave_Convexity },
417 { "0 0 10 0 0 10 -10 -10", SkPath::kConcave_Convexity },
418 };
419
420 for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
421 SkPath path;
422 setFromString(&path, gRec[i].fPathStr);
423 SkPath::Convexity c = SkPath::ComputeConvexity(path);
424 REPORTER_ASSERT(reporter, c == gRec[i].fExpectedConvexity);
425 }
426}
427
reed@google.com7e6c4d12012-05-10 14:05:43 +0000428static void test_isLine(skiatest::Reporter* reporter) {
429 SkPath path;
430 SkPoint pts[2];
431 const SkScalar value = SkIntToScalar(5);
432
433 REPORTER_ASSERT(reporter, !path.isLine(NULL));
434
435 // set some non-zero values
436 pts[0].set(value, value);
437 pts[1].set(value, value);
438 REPORTER_ASSERT(reporter, !path.isLine(pts));
439 // check that pts was untouched
440 REPORTER_ASSERT(reporter, pts[0].equals(value, value));
441 REPORTER_ASSERT(reporter, pts[1].equals(value, value));
442
443 const SkScalar moveX = SkIntToScalar(1);
444 const SkScalar moveY = SkIntToScalar(2);
445 SkASSERT(value != moveX && value != moveY);
446
447 path.moveTo(moveX, moveY);
448 REPORTER_ASSERT(reporter, !path.isLine(NULL));
449 REPORTER_ASSERT(reporter, !path.isLine(pts));
450 // check that pts was untouched
451 REPORTER_ASSERT(reporter, pts[0].equals(value, value));
452 REPORTER_ASSERT(reporter, pts[1].equals(value, value));
453
454 const SkScalar lineX = SkIntToScalar(2);
455 const SkScalar lineY = SkIntToScalar(2);
456 SkASSERT(value != lineX && value != lineY);
457
458 path.lineTo(lineX, lineY);
459 REPORTER_ASSERT(reporter, path.isLine(NULL));
460
461 REPORTER_ASSERT(reporter, !pts[0].equals(moveX, moveY));
462 REPORTER_ASSERT(reporter, !pts[1].equals(lineX, lineY));
463 REPORTER_ASSERT(reporter, path.isLine(pts));
464 REPORTER_ASSERT(reporter, pts[0].equals(moveX, moveY));
465 REPORTER_ASSERT(reporter, pts[1].equals(lineX, lineY));
466
467 path.lineTo(0, 0); // too many points/verbs
468 REPORTER_ASSERT(reporter, !path.isLine(NULL));
469 REPORTER_ASSERT(reporter, !path.isLine(pts));
470 REPORTER_ASSERT(reporter, pts[0].equals(moveX, moveY));
471 REPORTER_ASSERT(reporter, pts[1].equals(lineX, lineY));
472}
473
caryclark@google.comf1316942011-07-26 19:54:45 +0000474// Simple isRect test is inline TestPath, below.
475// test_isRect provides more extensive testing.
476static void test_isRect(skiatest::Reporter* reporter) {
477 // passing tests (all moveTo / lineTo...
478 SkPoint r1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
479 SkPoint r2[] = {{1, 0}, {1, 1}, {0, 1}, {0, 0}};
480 SkPoint r3[] = {{1, 1}, {0, 1}, {0, 0}, {1, 0}};
481 SkPoint r4[] = {{0, 1}, {0, 0}, {1, 0}, {1, 1}};
482 SkPoint r5[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}};
483 SkPoint r6[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
484 SkPoint r7[] = {{1, 1}, {1, 0}, {0, 0}, {0, 1}};
485 SkPoint r8[] = {{1, 0}, {0, 0}, {0, 1}, {1, 1}};
486 SkPoint r9[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
487 SkPoint ra[] = {{0, 0}, {0, .5f}, {0, 1}, {.5f, 1}, {1, 1}, {1, .5f},
488 {1, 0}, {.5f, 0}};
489 SkPoint rb[] = {{0, 0}, {.5f, 0}, {1, 0}, {1, .5f}, {1, 1}, {.5f, 1},
490 {0, 1}, {0, .5f}};
491 SkPoint rc[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}};
492 SkPoint rd[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}};
493 SkPoint re[] = {{0, 0}, {1, 0}, {1, 0}, {1, 1}, {0, 1}};
494
495 // failing tests
496 SkPoint f1[] = {{0, 0}, {1, 0}, {1, 1}}; // too few points
497 SkPoint f2[] = {{0, 0}, {1, 1}, {0, 1}, {1, 0}}; // diagonal
498 SkPoint f3[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}, {1, 0}}; // wraps
499 SkPoint f4[] = {{0, 0}, {1, 0}, {0, 0}, {1, 0}, {1, 1}, {0, 1}}; // backs up
500 SkPoint f5[] = {{0, 0}, {1, 0}, {1, 1}, {2, 0}}; // end overshoots
501 SkPoint f6[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 2}}; // end overshoots
502 SkPoint f7[] = {{0, 0}, {1, 0}, {1, 1}, {0, 2}}; // end overshoots
503 SkPoint f8[] = {{0, 0}, {1, 0}, {1, 1}, {1, 0}}; // 'L'
504
505 // failing, no close
506 SkPoint c1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}}; // close doesn't match
507 SkPoint c2[] = {{0, 0}, {1, 0}, {1, 2}, {0, 2}, {0, 1}}; // ditto
508
509 size_t testLen[] = {
510 sizeof(r1), sizeof(r2), sizeof(r3), sizeof(r4), sizeof(r5), sizeof(r6),
511 sizeof(r7), sizeof(r8), sizeof(r9), sizeof(ra), sizeof(rb), sizeof(rc),
512 sizeof(rd), sizeof(re),
513 sizeof(f1), sizeof(f2), sizeof(f3), sizeof(f4), sizeof(f5), sizeof(f6),
514 sizeof(f7), sizeof(f8),
515 sizeof(c1), sizeof(c2)
516 };
517 SkPoint* tests[] = {
518 r1, r2, r3, r4, r5, r6, r7, r8, r9, ra, rb, rc, rd, re,
519 f1, f2, f3, f4, f5, f6, f7, f8,
520 c1, c2
521 };
522 SkPoint* lastPass = re;
523 SkPoint* lastClose = f8;
524 bool fail = false;
525 bool close = true;
526 const size_t testCount = sizeof(tests) / sizeof(tests[0]);
527 size_t index;
528 for (size_t testIndex = 0; testIndex < testCount; ++testIndex) {
529 SkPath path;
530 path.moveTo(tests[testIndex][0].fX, tests[testIndex][0].fY);
531 for (index = 1; index < testLen[testIndex] / sizeof(SkPoint); ++index) {
532 path.lineTo(tests[testIndex][index].fX, tests[testIndex][index].fY);
533 }
534 if (close) {
535 path.close();
536 }
537 REPORTER_ASSERT(reporter, fail ^ path.isRect(0));
538 if (tests[testIndex] == lastPass) {
539 fail = true;
540 }
541 if (tests[testIndex] == lastClose) {
542 close = false;
543 }
544 }
545
546 // fail, close then line
547 SkPath path1;
548 path1.moveTo(r1[0].fX, r1[0].fY);
549 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
550 path1.lineTo(r1[index].fX, r1[index].fY);
551 }
552 path1.close();
553 path1.lineTo(1, 0);
554 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
555
556 // fail, move in the middle
557 path1.reset();
558 path1.moveTo(r1[0].fX, r1[0].fY);
559 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
560 if (index == 2) {
561 path1.moveTo(1, .5f);
562 }
563 path1.lineTo(r1[index].fX, r1[index].fY);
564 }
565 path1.close();
566 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
567
568 // fail, move on the edge
569 path1.reset();
570 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
571 path1.moveTo(r1[index - 1].fX, r1[index - 1].fY);
572 path1.lineTo(r1[index].fX, r1[index].fY);
573 }
574 path1.close();
575 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
576
577 // fail, quad
578 path1.reset();
579 path1.moveTo(r1[0].fX, r1[0].fY);
580 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
581 if (index == 2) {
582 path1.quadTo(1, .5f, 1, .5f);
583 }
584 path1.lineTo(r1[index].fX, r1[index].fY);
585 }
586 path1.close();
587 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
588
589 // fail, cubic
590 path1.reset();
591 path1.moveTo(r1[0].fX, r1[0].fY);
592 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
593 if (index == 2) {
594 path1.cubicTo(1, .5f, 1, .5f, 1, .5f);
595 }
596 path1.lineTo(r1[index].fX, r1[index].fY);
597 }
598 path1.close();
599 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
600}
601
reed@google.com53effc52011-09-21 19:05:12 +0000602static void test_flattening(skiatest::Reporter* reporter) {
603 SkPath p;
604
605 static const SkPoint pts[] = {
606 { 0, 0 },
607 { SkIntToScalar(10), SkIntToScalar(10) },
608 { SkIntToScalar(20), SkIntToScalar(10) }, { SkIntToScalar(20), 0 },
609 { 0, 0 }, { 0, SkIntToScalar(10) }, { SkIntToScalar(1), SkIntToScalar(10) }
610 };
611 p.moveTo(pts[0]);
612 p.lineTo(pts[1]);
613 p.quadTo(pts[2], pts[3]);
614 p.cubicTo(pts[4], pts[5], pts[6]);
615
616 SkWriter32 writer(100);
617 p.flatten(writer);
618 size_t size = writer.size();
619 SkAutoMalloc storage(size);
620 writer.flatten(storage.get());
621 SkReader32 reader(storage.get(), size);
622
623 SkPath p1;
624 REPORTER_ASSERT(reporter, p1 != p);
625 p1.unflatten(reader);
626 REPORTER_ASSERT(reporter, p1 == p);
627}
628
629static void test_transform(skiatest::Reporter* reporter) {
630 SkPath p, p1;
631
632 static const SkPoint pts[] = {
633 { 0, 0 },
634 { SkIntToScalar(10), SkIntToScalar(10) },
635 { SkIntToScalar(20), SkIntToScalar(10) }, { SkIntToScalar(20), 0 },
636 { 0, 0 }, { 0, SkIntToScalar(10) }, { SkIntToScalar(1), SkIntToScalar(10) }
637 };
638 p.moveTo(pts[0]);
639 p.lineTo(pts[1]);
640 p.quadTo(pts[2], pts[3]);
641 p.cubicTo(pts[4], pts[5], pts[6]);
642
643 SkMatrix matrix;
644 matrix.reset();
645 p.transform(matrix, &p1);
646 REPORTER_ASSERT(reporter, p == p1);
647
648 matrix.setScale(SK_Scalar1 * 2, SK_Scalar1 * 3);
649 p.transform(matrix, &p1);
650 SkPoint pts1[7];
651 int count = p1.getPoints(pts1, 7);
652 REPORTER_ASSERT(reporter, 7 == count);
653 for (int i = 0; i < count; ++i) {
654 SkPoint newPt = SkPoint::Make(pts[i].fX * 2, pts[i].fY * 3);
655 REPORTER_ASSERT(reporter, newPt == pts1[i]);
656 }
657}
658
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000659static void test_zero_length_paths(skiatest::Reporter* reporter) {
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000660 SkPath p;
661 SkPoint pt;
662 SkRect bounds;
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000663
664 // Lone moveTo case
665 p.moveTo(SK_Scalar1, SK_Scalar1);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000666 REPORTER_ASSERT(reporter, !p.isEmpty());
667 REPORTER_ASSERT(reporter, 1 == p.countPoints());
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000668 p.getLastPt(&pt);
669 REPORTER_ASSERT(reporter, pt.fX == SK_Scalar1);
670 REPORTER_ASSERT(reporter, pt.fY == SK_Scalar1);
671 bounds.set(0, 0, 0, 0);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000672 REPORTER_ASSERT(reporter, bounds == p.getBounds());
673
674 // MoveTo-MoveTo case
675 p.moveTo(SK_Scalar1*2, SK_Scalar1);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000676 REPORTER_ASSERT(reporter, !p.isEmpty());
677 REPORTER_ASSERT(reporter, 2 == p.countPoints());
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000678 p.getLastPt(&pt);
679 REPORTER_ASSERT(reporter, pt.fX == SK_Scalar1*2);
680 REPORTER_ASSERT(reporter, pt.fY == SK_Scalar1);
681 bounds.set(SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000682 REPORTER_ASSERT(reporter, bounds == p.getBounds());
683
684 // moveTo-close case
685 p.reset();
686 p.moveTo(SK_Scalar1, SK_Scalar1);
687 p.close();
688 bounds.set(0, 0, 0, 0);
689 REPORTER_ASSERT(reporter, !p.isEmpty());
690 REPORTER_ASSERT(reporter, 1 == p.countPoints());
691 REPORTER_ASSERT(reporter, bounds == p.getBounds());
692
693 // moveTo-close-moveTo-close case
694 p.moveTo(SK_Scalar1*2, SK_Scalar1);
695 p.close();
schenney@chromium.org32879492011-12-20 15:33:11 +0000696 bounds.set(SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000697 REPORTER_ASSERT(reporter, !p.isEmpty());
698 REPORTER_ASSERT(reporter, 2 == p.countPoints());
699 REPORTER_ASSERT(reporter, bounds == p.getBounds());
700
701 // moveTo-line case
702 p.reset();
703 p.moveTo(SK_Scalar1, SK_Scalar1);
704 p.lineTo(SK_Scalar1, SK_Scalar1);
705 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
706 REPORTER_ASSERT(reporter, !p.isEmpty());
707 REPORTER_ASSERT(reporter, 2 == p.countPoints());
708 REPORTER_ASSERT(reporter, bounds == p.getBounds());
709
710 // moveTo-lineTo-moveTo-lineTo case
711 p.moveTo(SK_Scalar1*2, SK_Scalar1);
712 p.lineTo(SK_Scalar1*2, SK_Scalar1);
713 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
714 REPORTER_ASSERT(reporter, !p.isEmpty());
715 REPORTER_ASSERT(reporter, 4 == p.countPoints());
716 REPORTER_ASSERT(reporter, bounds == p.getBounds());
717
718 // moveTo-line-close case
719 p.reset();
720 p.moveTo(SK_Scalar1, SK_Scalar1);
721 p.lineTo(SK_Scalar1, SK_Scalar1);
722 p.close();
723 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
724 REPORTER_ASSERT(reporter, !p.isEmpty());
725 REPORTER_ASSERT(reporter, 2 == p.countPoints());
726 REPORTER_ASSERT(reporter, bounds == p.getBounds());
727
728 // moveTo-line-close-moveTo-line-close case
729 p.moveTo(SK_Scalar1*2, SK_Scalar1);
730 p.lineTo(SK_Scalar1*2, SK_Scalar1);
731 p.close();
732 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
733 REPORTER_ASSERT(reporter, !p.isEmpty());
734 REPORTER_ASSERT(reporter, 4 == p.countPoints());
735 REPORTER_ASSERT(reporter, bounds == p.getBounds());
736
737 // moveTo-quadTo case
738 p.reset();
739 p.moveTo(SK_Scalar1, SK_Scalar1);
740 p.quadTo(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
741 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
742 REPORTER_ASSERT(reporter, !p.isEmpty());
743 REPORTER_ASSERT(reporter, 3 == p.countPoints());
744 REPORTER_ASSERT(reporter, bounds == p.getBounds());
745
746 // moveTo-quadTo-close case
747 p.close();
748 REPORTER_ASSERT(reporter, !p.isEmpty());
749 REPORTER_ASSERT(reporter, 3 == p.countPoints());
750 REPORTER_ASSERT(reporter, bounds == p.getBounds());
751
752 // moveTo-quadTo-moveTo-quadTo case
753 p.reset();
754 p.moveTo(SK_Scalar1, SK_Scalar1);
755 p.quadTo(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
756 p.moveTo(SK_Scalar1*2, SK_Scalar1);
757 p.quadTo(SK_Scalar1*2, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
758 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
759 REPORTER_ASSERT(reporter, !p.isEmpty());
760 REPORTER_ASSERT(reporter, 6 == p.countPoints());
761 REPORTER_ASSERT(reporter, bounds == p.getBounds());
762
763 // moveTo-cubicTo case
764 p.reset();
765 p.moveTo(SK_Scalar1, SK_Scalar1);
766 p.cubicTo(SK_Scalar1, SK_Scalar1,
767 SK_Scalar1, SK_Scalar1,
768 SK_Scalar1, SK_Scalar1);
769 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
770 REPORTER_ASSERT(reporter, !p.isEmpty());
771 REPORTER_ASSERT(reporter, 4 == p.countPoints());
772 REPORTER_ASSERT(reporter, bounds == p.getBounds());
773
774 // moveTo-quadTo-close case
775 p.close();
776 REPORTER_ASSERT(reporter, !p.isEmpty());
777 REPORTER_ASSERT(reporter, 4 == p.countPoints());
778 REPORTER_ASSERT(reporter, bounds == p.getBounds());
779
780 // moveTo-quadTo-moveTo-quadTo case
781 p.reset();
782 p.moveTo(SK_Scalar1, SK_Scalar1);
783 p.cubicTo(SK_Scalar1, SK_Scalar1,
784 SK_Scalar1, SK_Scalar1,
785 SK_Scalar1, SK_Scalar1);
786 p.moveTo(SK_Scalar1*2, SK_Scalar1);
787 p.cubicTo(SK_Scalar1*2, SK_Scalar1,
788 SK_Scalar1*2, SK_Scalar1,
789 SK_Scalar1*2, SK_Scalar1);
790 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
791 REPORTER_ASSERT(reporter, !p.isEmpty());
792 REPORTER_ASSERT(reporter, 8 == p.countPoints());
793 REPORTER_ASSERT(reporter, bounds == p.getBounds());
794}
795
796struct SegmentInfo {
797 SkPath fPath;
798 int fPointCount;
799};
800
reed@google.com10296cc2011-09-21 12:29:05 +0000801#define kCurveSegmentMask (SkPath::kQuad_SegmentMask | SkPath::kCubic_SegmentMask)
802
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000803static void test_segment_masks(skiatest::Reporter* reporter) {
804 SkPath p;
805 p.moveTo(0, 0);
806 p.quadTo(100, 100, 200, 200);
807 REPORTER_ASSERT(reporter, SkPath::kQuad_SegmentMask == p.getSegmentMasks());
808 REPORTER_ASSERT(reporter, !p.isEmpty());
809 p.cubicTo(100, 100, 200, 200, 300, 300);
810 REPORTER_ASSERT(reporter, kCurveSegmentMask == p.getSegmentMasks());
811 REPORTER_ASSERT(reporter, !p.isEmpty());
812 p.reset();
813 p.moveTo(0, 0);
814 p.cubicTo(100, 100, 200, 200, 300, 300);
815 REPORTER_ASSERT(reporter, SkPath::kCubic_SegmentMask == p.getSegmentMasks());
816 REPORTER_ASSERT(reporter, !p.isEmpty());
817}
818
819static void test_iter(skiatest::Reporter* reporter) {
820 SkPath p;
821 SkPoint pts[4];
822
823 // Test an iterator with no path
824 SkPath::Iter noPathIter;
825 REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
826 // Test that setting an empty path works
827 noPathIter.setPath(p, false);
828 REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
829 // Test that close path makes no difference for an empty path
830 noPathIter.setPath(p, true);
831 REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
832
833 // Test an iterator with an initial empty path
834 SkPath::Iter iter(p, false);
835 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
836
837 // Test that close path makes no difference
838 SkPath::Iter forceCloseIter(p, true);
839 REPORTER_ASSERT(reporter, forceCloseIter.next(pts) == SkPath::kDone_Verb);
840
841 // Test that a move-only path produces nothing when iterated.
842 p.moveTo(SK_Scalar1, 0);
843 iter.setPath(p, false);
844 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
845
846 // No matter how many moves we add, we should still get nothing back.
847 p.moveTo(SK_Scalar1*2, 0);
848 p.moveTo(SK_Scalar1*3, 0);
849 p.moveTo(SK_Scalar1*4, 0);
850 p.moveTo(SK_Scalar1*5, 0);
851 iter.setPath(p, false);
852 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
853
854 // Nor should force closing
855 forceCloseIter.setPath(p, true);
856 REPORTER_ASSERT(reporter, forceCloseIter.next(pts) == SkPath::kDone_Verb);
857
858 // Initial closes should be ignored
859 p.reset();
860 p.close();
861 iter.setPath(p, false);
862 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
863 // Even if force closed
864 forceCloseIter.setPath(p, true);
865 REPORTER_ASSERT(reporter, forceCloseIter.next(pts) == SkPath::kDone_Verb);
866
867 // Move/close sequences should also be ignored
868 p.reset();
869 p.close();
870 p.moveTo(SK_Scalar1, 0);
871 p.close();
872 p.close();
873 p.moveTo(SK_Scalar1*2, 0);
874 p.close();
875 p.moveTo(SK_Scalar1*3, 0);
876 p.moveTo(SK_Scalar1*4, 0);
877 p.close();
878 iter.setPath(p, false);
879 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
880 // Even if force closed
881 forceCloseIter.setPath(p, true);
882 REPORTER_ASSERT(reporter, forceCloseIter.next(pts) == SkPath::kDone_Verb);
883
884 // The GM degeneratesegments.cpp test is more extensive
885}
886
887static void test_raw_iter(skiatest::Reporter* reporter) {
888 SkPath p;
889 SkPoint pts[4];
890
891 // Test an iterator with no path
892 SkPath::RawIter noPathIter;
893 REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
894 // Test that setting an empty path works
895 noPathIter.setPath(p);
896 REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
897
898 // Test an iterator with an initial empty path
899 SkPath::RawIter iter(p);
900 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
901
902 // Test that a move-only path returns the move.
903 p.moveTo(SK_Scalar1, 0);
904 iter.setPath(p);
905 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
906 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
907 REPORTER_ASSERT(reporter, pts[0].fY == 0);
908 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
909
910 // No matter how many moves we add, we should get them all back
911 p.moveTo(SK_Scalar1*2, SK_Scalar1);
912 p.moveTo(SK_Scalar1*3, SK_Scalar1*2);
913 iter.setPath(p);
914 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
915 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
916 REPORTER_ASSERT(reporter, pts[0].fY == 0);
917 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
918 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2);
919 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1);
920 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
921 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*3);
922 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*2);
923 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
924
925 // Initial close is never ever stored
926 p.reset();
927 p.close();
928 iter.setPath(p);
929 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
930
931 // Move/close sequences
932 p.reset();
933 p.close(); // Not stored, no purpose
934 p.moveTo(SK_Scalar1, 0);
935 p.close();
936 p.close(); // Not stored, no purpose
937 p.moveTo(SK_Scalar1*2, SK_Scalar1);
938 p.close();
939 p.moveTo(SK_Scalar1*3, SK_Scalar1*2);
940 p.moveTo(SK_Scalar1*4, SK_Scalar1*3);
941 p.close();
942 iter.setPath(p);
943 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
944 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
945 REPORTER_ASSERT(reporter, pts[0].fY == 0);
946 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kClose_Verb);
947 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
948 REPORTER_ASSERT(reporter, pts[0].fY == 0);
949 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
950 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2);
951 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1);
952 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kClose_Verb);
953 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2);
954 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1);
955 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
956 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*3);
957 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*2);
958 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
959 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*4);
960 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*3);
961 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kClose_Verb);
962 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*4);
963 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*3);
964 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
965
966 // Generate random paths and verify
967 SkPoint randomPts[25];
968 for (int i = 0; i < 5; ++i) {
969 for (int j = 0; j < 5; ++j) {
970 randomPts[i*5+j].set(SK_Scalar1*i, SK_Scalar1*j);
971 }
972 }
973
974 // Max of 10 segments, max 3 points per segment
975 SkRandom rand(9876543);
976 SkPoint expectedPts[31]; // May have leading moveTo
reed@google.comd335d1d2012-01-12 18:17:11 +0000977 SkPath::Verb expectedVerbs[22]; // May have leading moveTo
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000978 SkPath::Verb nextVerb;
reed@google.comd335d1d2012-01-12 18:17:11 +0000979
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000980 for (int i = 0; i < 500; ++i) {
981 p.reset();
982 bool lastWasClose = true;
983 bool haveMoveTo = false;
reed@google.comd335d1d2012-01-12 18:17:11 +0000984 SkPoint lastMoveToPt = { 0, 0 };
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000985 int numPoints = 0;
986 int numVerbs = (rand.nextU() >> 16) % 10;
987 int numIterVerbs = 0;
988 for (int j = 0; j < numVerbs; ++j) {
989 do {
990 nextVerb = static_cast<SkPath::Verb>((rand.nextU() >> 16) % SkPath::kDone_Verb);
991 } while (lastWasClose && nextVerb == SkPath::kClose_Verb);
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000992 switch (nextVerb) {
993 case SkPath::kMove_Verb:
994 expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
995 p.moveTo(expectedPts[numPoints]);
reed@google.comd335d1d2012-01-12 18:17:11 +0000996 lastMoveToPt = expectedPts[numPoints];
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000997 numPoints += 1;
998 lastWasClose = false;
999 haveMoveTo = true;
1000 break;
1001 case SkPath::kLine_Verb:
1002 if (!haveMoveTo) {
reed@google.comd335d1d2012-01-12 18:17:11 +00001003 expectedPts[numPoints++] = lastMoveToPt;
schenney@chromium.org6630d8d2012-01-04 21:05:51 +00001004 expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
1005 haveMoveTo = true;
1006 }
1007 expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
1008 p.lineTo(expectedPts[numPoints]);
1009 numPoints += 1;
1010 lastWasClose = false;
1011 break;
1012 case SkPath::kQuad_Verb:
1013 if (!haveMoveTo) {
reed@google.comd335d1d2012-01-12 18:17:11 +00001014 expectedPts[numPoints++] = lastMoveToPt;
schenney@chromium.org6630d8d2012-01-04 21:05:51 +00001015 expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
1016 haveMoveTo = true;
1017 }
1018 expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
1019 expectedPts[numPoints + 1] = randomPts[(rand.nextU() >> 16) % 25];
1020 p.quadTo(expectedPts[numPoints], expectedPts[numPoints + 1]);
1021 numPoints += 2;
1022 lastWasClose = false;
1023 break;
1024 case SkPath::kCubic_Verb:
1025 if (!haveMoveTo) {
reed@google.comd335d1d2012-01-12 18:17:11 +00001026 expectedPts[numPoints++] = lastMoveToPt;
schenney@chromium.org6630d8d2012-01-04 21:05:51 +00001027 expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
1028 haveMoveTo = true;
1029 }
1030 expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
1031 expectedPts[numPoints + 1] = randomPts[(rand.nextU() >> 16) % 25];
1032 expectedPts[numPoints + 2] = randomPts[(rand.nextU() >> 16) % 25];
1033 p.cubicTo(expectedPts[numPoints], expectedPts[numPoints + 1],
1034 expectedPts[numPoints + 2]);
1035 numPoints += 3;
1036 lastWasClose = false;
1037 break;
1038 case SkPath::kClose_Verb:
1039 p.close();
reed@google.comd335d1d2012-01-12 18:17:11 +00001040 haveMoveTo = false;
schenney@chromium.org6630d8d2012-01-04 21:05:51 +00001041 lastWasClose = true;
1042 break;
1043 default:;
1044 }
1045 expectedVerbs[numIterVerbs++] = nextVerb;
1046 }
1047
1048 iter.setPath(p);
1049 numVerbs = numIterVerbs;
1050 numIterVerbs = 0;
1051 int numIterPts = 0;
1052 SkPoint lastMoveTo;
1053 SkPoint lastPt;
1054 lastMoveTo.set(0, 0);
1055 lastPt.set(0, 0);
1056 while ((nextVerb = iter.next(pts)) != SkPath::kDone_Verb) {
1057 REPORTER_ASSERT(reporter, nextVerb == expectedVerbs[numIterVerbs]);
1058 numIterVerbs++;
1059 switch (nextVerb) {
1060 case SkPath::kMove_Verb:
1061 REPORTER_ASSERT(reporter, numIterPts < numPoints);
1062 REPORTER_ASSERT(reporter, pts[0] == expectedPts[numIterPts]);
1063 lastPt = lastMoveTo = pts[0];
1064 numIterPts += 1;
1065 break;
1066 case SkPath::kLine_Verb:
1067 REPORTER_ASSERT(reporter, numIterPts < numPoints + 1);
1068 REPORTER_ASSERT(reporter, pts[0] == lastPt);
1069 REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]);
1070 lastPt = pts[1];
1071 numIterPts += 1;
1072 break;
1073 case SkPath::kQuad_Verb:
1074 REPORTER_ASSERT(reporter, numIterPts < numPoints + 2);
1075 REPORTER_ASSERT(reporter, pts[0] == lastPt);
1076 REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]);
1077 REPORTER_ASSERT(reporter, pts[2] == expectedPts[numIterPts + 1]);
1078 lastPt = pts[2];
1079 numIterPts += 2;
1080 break;
1081 case SkPath::kCubic_Verb:
1082 REPORTER_ASSERT(reporter, numIterPts < numPoints + 3);
1083 REPORTER_ASSERT(reporter, pts[0] == lastPt);
1084 REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]);
1085 REPORTER_ASSERT(reporter, pts[2] == expectedPts[numIterPts + 1]);
1086 REPORTER_ASSERT(reporter, pts[3] == expectedPts[numIterPts + 2]);
1087 lastPt = pts[3];
1088 numIterPts += 3;
1089 break;
1090 case SkPath::kClose_Verb:
1091 REPORTER_ASSERT(reporter, pts[0] == lastMoveTo);
1092 lastPt = lastMoveTo;
1093 break;
1094 default:;
1095 }
1096 }
1097 REPORTER_ASSERT(reporter, numIterPts == numPoints);
1098 REPORTER_ASSERT(reporter, numIterVerbs == numVerbs);
1099 }
1100}
1101
bsalomon@google.com6aa29652012-04-18 13:29:52 +00001102static void check_for_circle(skiatest::Reporter* reporter,
1103 const SkPath& path, bool expected) {
1104 SkRect rect;
1105 REPORTER_ASSERT(reporter, path.isOval(&rect) == expected);
1106 if (expected) {
1107 REPORTER_ASSERT(reporter, rect.height() == rect.width());
1108 }
1109}
1110
1111static void test_circle_skew(skiatest::Reporter* reporter,
1112 const SkPath& path) {
1113 SkPath tmp;
1114
1115 SkMatrix m;
1116 m.setSkew(SkIntToScalar(3), SkIntToScalar(5));
1117 path.transform(m, &tmp);
1118 check_for_circle(reporter, tmp, false);
1119}
1120
1121static void test_circle_translate(skiatest::Reporter* reporter,
1122 const SkPath& path) {
1123 SkPath tmp;
1124
1125 // translate at small offset
1126 SkMatrix m;
1127 m.setTranslate(SkIntToScalar(15), SkIntToScalar(15));
1128 path.transform(m, &tmp);
1129 check_for_circle(reporter, tmp, true);
1130
1131 tmp.reset();
1132 m.reset();
1133
1134 // translate at a relatively big offset
1135 m.setTranslate(SkIntToScalar(1000), SkIntToScalar(1000));
1136 path.transform(m, &tmp);
1137 check_for_circle(reporter, tmp, true);
1138}
1139
1140static void test_circle_rotate(skiatest::Reporter* reporter,
1141 const SkPath& path) {
1142 for (int angle = 0; angle < 360; ++angle) {
1143 SkPath tmp;
1144 SkMatrix m;
1145 m.setRotate(SkIntToScalar(angle));
1146 path.transform(m, &tmp);
1147
1148 // TODO: a rotated circle whose rotated angle is not a mutiple of 90
1149 // degrees is not an oval anymore, this can be improved. we made this
1150 // for the simplicity of our implementation.
1151 if (angle % 90 == 0) {
1152 check_for_circle(reporter, tmp, true);
1153 } else {
1154 check_for_circle(reporter, tmp, false);
1155 }
1156 }
1157}
1158
1159static void test_circle_with_direction(skiatest::Reporter* reporter,
1160 SkPath::Direction dir) {
1161 SkPath path;
1162
1163 // circle at origin
1164 path.addCircle(0, 0, SkIntToScalar(20), dir);
1165 check_for_circle(reporter, path, true);
1166 test_circle_rotate(reporter, path);
1167 test_circle_translate(reporter, path);
1168 test_circle_skew(reporter, path);
1169
1170 // circle at an offset at (10, 10)
1171 path.reset();
1172 path.addCircle(SkIntToScalar(10), SkIntToScalar(10),
1173 SkIntToScalar(20), dir);
1174 check_for_circle(reporter, path, true);
1175 test_circle_rotate(reporter, path);
1176 test_circle_translate(reporter, path);
1177 test_circle_skew(reporter, path);
1178}
1179
1180static void test_circle_with_add_paths(skiatest::Reporter* reporter) {
1181 SkPath path;
1182 SkPath circle;
1183 SkPath rect;
1184 SkPath empty;
1185
1186 circle.addCircle(0, 0, SkIntToScalar(10), SkPath::kCW_Direction);
1187 rect.addRect(SkIntToScalar(5), SkIntToScalar(5),
1188 SkIntToScalar(20), SkIntToScalar(20), SkPath::kCW_Direction);
1189
1190 SkMatrix translate;
1191 translate.setTranslate(SkIntToScalar(12), SkIntToScalar(12));
1192
1193 // For simplicity, all the path concatenation related operations
1194 // would mark it non-circle, though in theory it's still a circle.
1195
1196 // empty + circle (translate)
1197 path = empty;
1198 path.addPath(circle, translate);
1199 check_for_circle(reporter, path, false);
1200
1201 // circle + empty (translate)
1202 path = circle;
1203 path.addPath(empty, translate);
1204 check_for_circle(reporter, path, false);
1205
1206 // test reverseAddPath
1207 path = circle;
1208 path.reverseAddPath(rect);
1209 check_for_circle(reporter, path, false);
1210}
1211
1212static void test_circle(skiatest::Reporter* reporter) {
1213 test_circle_with_direction(reporter, SkPath::kCW_Direction);
1214 test_circle_with_direction(reporter, SkPath::kCCW_Direction);
1215
1216 // multiple addCircle()
1217 SkPath path;
1218 path.addCircle(0, 0, SkIntToScalar(10), SkPath::kCW_Direction);
1219 path.addCircle(0, 0, SkIntToScalar(20), SkPath::kCW_Direction);
1220 check_for_circle(reporter, path, false);
1221
1222 // some extra lineTo() would make isOval() fail
1223 path.reset();
1224 path.addCircle(0, 0, SkIntToScalar(10), SkPath::kCW_Direction);
1225 path.lineTo(0, 0);
1226 check_for_circle(reporter, path, false);
1227
1228 // not back to the original point
1229 path.reset();
1230 path.addCircle(0, 0, SkIntToScalar(10), SkPath::kCW_Direction);
1231 path.setLastPt(SkIntToScalar(5), SkIntToScalar(5));
1232 check_for_circle(reporter, path, false);
1233
1234 test_circle_with_add_paths(reporter);
1235}
1236
1237static void test_oval(skiatest::Reporter* reporter) {
1238 SkRect rect;
1239 SkMatrix m;
1240 SkPath path;
1241
1242 rect = SkRect::MakeWH(SkIntToScalar(30), SkIntToScalar(50));
1243 path.addOval(rect);
1244
1245 REPORTER_ASSERT(reporter, path.isOval(NULL));
1246
1247 m.setRotate(SkIntToScalar(90));
1248 SkPath tmp;
1249 path.transform(m, &tmp);
1250 // an oval rotated 90 degrees is still an oval.
1251 REPORTER_ASSERT(reporter, tmp.isOval(NULL));
1252
1253 m.reset();
1254 m.setRotate(SkIntToScalar(30));
1255 tmp.reset();
1256 path.transform(m, &tmp);
1257 // an oval rotated 30 degrees is not an oval anymore.
1258 REPORTER_ASSERT(reporter, !tmp.isOval(NULL));
1259
1260 // since empty path being transformed.
1261 path.reset();
1262 tmp.reset();
1263 m.reset();
1264 path.transform(m, &tmp);
1265 REPORTER_ASSERT(reporter, !tmp.isOval(NULL));
1266
1267 // empty path is not an oval
1268 tmp.reset();
1269 REPORTER_ASSERT(reporter, !tmp.isOval(NULL));
1270
1271 // only has moveTo()s
1272 tmp.reset();
1273 tmp.moveTo(0, 0);
1274 tmp.moveTo(SkIntToScalar(10), SkIntToScalar(10));
1275 REPORTER_ASSERT(reporter, !tmp.isOval(NULL));
1276
1277 // mimic WebKit's calling convention,
1278 // call moveTo() first and then call addOval()
1279 path.reset();
1280 path.moveTo(0, 0);
1281 path.addOval(rect);
1282 REPORTER_ASSERT(reporter, path.isOval(NULL));
1283
1284 // copy path
1285 path.reset();
1286 tmp.reset();
1287 tmp.addOval(rect);
1288 path = tmp;
1289 REPORTER_ASSERT(reporter, path.isOval(NULL));
1290}
1291
reed@google.com04863fa2011-05-15 04:08:24 +00001292void TestPath(skiatest::Reporter* reporter) {
reed@android.com60bc6d52010-02-11 11:09:39 +00001293 {
1294 SkSize size;
1295 size.fWidth = 3.4f;
1296 size.width();
1297 size = SkSize::Make(3,4);
1298 SkISize isize = SkISize::Make(3,4);
1299 }
1300
1301 SkTSize<SkScalar>::Make(3,4);
1302
reed@android.com3abec1d2009-03-02 05:36:20 +00001303 SkPath p, p2;
1304 SkRect bounds, bounds2;
reed@android.com80e39a72009-04-02 16:59:40 +00001305
reed@android.com3abec1d2009-03-02 05:36:20 +00001306 REPORTER_ASSERT(reporter, p.isEmpty());
schenney@chromium.org4da06ab2011-12-20 15:14:18 +00001307 REPORTER_ASSERT(reporter, 0 == p.countPoints());
reed@google.com10296cc2011-09-21 12:29:05 +00001308 REPORTER_ASSERT(reporter, 0 == p.getSegmentMasks());
reed@google.comb54455e2011-05-16 14:16:04 +00001309 REPORTER_ASSERT(reporter, p.isConvex());
reed@android.com3abec1d2009-03-02 05:36:20 +00001310 REPORTER_ASSERT(reporter, p.getFillType() == SkPath::kWinding_FillType);
1311 REPORTER_ASSERT(reporter, !p.isInverseFillType());
1312 REPORTER_ASSERT(reporter, p == p2);
1313 REPORTER_ASSERT(reporter, !(p != p2));
1314
reed@android.comd252db02009-04-01 18:31:44 +00001315 REPORTER_ASSERT(reporter, p.getBounds().isEmpty());
reed@android.com80e39a72009-04-02 16:59:40 +00001316
reed@android.com3abec1d2009-03-02 05:36:20 +00001317 bounds.set(0, 0, SK_Scalar1, SK_Scalar1);
reed@android.com6b82d1a2009-06-03 02:35:01 +00001318
reed@android.com6b82d1a2009-06-03 02:35:01 +00001319 p.addRoundRect(bounds, SK_Scalar1, SK_Scalar1);
1320 check_convex_bounds(reporter, p, bounds);
reed@google.com10296cc2011-09-21 12:29:05 +00001321 // we have quads or cubics
1322 REPORTER_ASSERT(reporter, p.getSegmentMasks() & kCurveSegmentMask);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +00001323 REPORTER_ASSERT(reporter, !p.isEmpty());
reed@google.com62047cf2011-02-07 19:39:09 +00001324
reed@android.com6b82d1a2009-06-03 02:35:01 +00001325 p.reset();
reed@google.com10296cc2011-09-21 12:29:05 +00001326 REPORTER_ASSERT(reporter, 0 == p.getSegmentMasks());
schenney@chromium.org4da06ab2011-12-20 15:14:18 +00001327 REPORTER_ASSERT(reporter, p.isEmpty());
reed@google.com10296cc2011-09-21 12:29:05 +00001328
reed@android.com6b82d1a2009-06-03 02:35:01 +00001329 p.addOval(bounds);
1330 check_convex_bounds(reporter, p, bounds);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +00001331 REPORTER_ASSERT(reporter, !p.isEmpty());
reed@google.com62047cf2011-02-07 19:39:09 +00001332
reed@android.com6b82d1a2009-06-03 02:35:01 +00001333 p.reset();
reed@android.com3abec1d2009-03-02 05:36:20 +00001334 p.addRect(bounds);
reed@android.com6b82d1a2009-06-03 02:35:01 +00001335 check_convex_bounds(reporter, p, bounds);
reed@google.com10296cc2011-09-21 12:29:05 +00001336 // we have only lines
1337 REPORTER_ASSERT(reporter, SkPath::kLine_SegmentMask == p.getSegmentMasks());
schenney@chromium.org4da06ab2011-12-20 15:14:18 +00001338 REPORTER_ASSERT(reporter, !p.isEmpty());
reed@android.com3abec1d2009-03-02 05:36:20 +00001339
1340 REPORTER_ASSERT(reporter, p != p2);
1341 REPORTER_ASSERT(reporter, !(p == p2));
1342
1343 // does getPoints return the right result
1344 REPORTER_ASSERT(reporter, p.getPoints(NULL, 5) == 4);
1345 SkPoint pts[4];
1346 int count = p.getPoints(pts, 4);
1347 REPORTER_ASSERT(reporter, count == 4);
1348 bounds2.set(pts, 4);
1349 REPORTER_ASSERT(reporter, bounds == bounds2);
reed@android.com80e39a72009-04-02 16:59:40 +00001350
reed@android.com3abec1d2009-03-02 05:36:20 +00001351 bounds.offset(SK_Scalar1*3, SK_Scalar1*4);
1352 p.offset(SK_Scalar1*3, SK_Scalar1*4);
reed@android.comd252db02009-04-01 18:31:44 +00001353 REPORTER_ASSERT(reporter, bounds == p.getBounds());
reed@android.com3abec1d2009-03-02 05:36:20 +00001354
reed@android.com3abec1d2009-03-02 05:36:20 +00001355 REPORTER_ASSERT(reporter, p.isRect(NULL));
caryclark@google.comf1316942011-07-26 19:54:45 +00001356 bounds2.setEmpty();
reed@android.com3abec1d2009-03-02 05:36:20 +00001357 REPORTER_ASSERT(reporter, p.isRect(&bounds2));
1358 REPORTER_ASSERT(reporter, bounds == bounds2);
reed@android.com80e39a72009-04-02 16:59:40 +00001359
reed@android.com3abec1d2009-03-02 05:36:20 +00001360 // now force p to not be a rect
1361 bounds.set(0, 0, SK_Scalar1/2, SK_Scalar1/2);
1362 p.addRect(bounds);
1363 REPORTER_ASSERT(reporter, !p.isRect(NULL));
reed@android.com3abec1d2009-03-02 05:36:20 +00001364
reed@google.com7e6c4d12012-05-10 14:05:43 +00001365 test_isLine(reporter);
1366 test_isRect(reporter);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +00001367 test_zero_length_paths(reporter);
reed@google.comcabaf1d2012-01-11 21:03:05 +00001368 test_direction(reporter);
reed@google.com04863fa2011-05-15 04:08:24 +00001369 test_convexity(reporter);
reed@google.com7c424812011-05-15 04:38:34 +00001370 test_convexity2(reporter);
bsalomon@google.comb3b8dfa2011-07-13 17:44:36 +00001371 test_close(reporter);
schenney@chromium.org6630d8d2012-01-04 21:05:51 +00001372 test_segment_masks(reporter);
reed@google.com53effc52011-09-21 19:05:12 +00001373 test_flattening(reporter);
1374 test_transform(reporter);
reed@google.com3563c9e2011-11-14 19:34:57 +00001375 test_bounds(reporter);
schenney@chromium.org6630d8d2012-01-04 21:05:51 +00001376 test_iter(reporter);
1377 test_raw_iter(reporter);
bsalomon@google.com6aa29652012-04-18 13:29:52 +00001378 test_circle(reporter);
1379 test_oval(reporter);
reed@android.com3abec1d2009-03-02 05:36:20 +00001380}
1381
1382#include "TestClassDef.h"
1383DEFINE_TESTCLASS("Path", PathTestClass, TestPath)