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