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 18 /** 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 */ 23 static 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 33 static 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[] = { 56 "M 10 10 L 10 10 Q 20 10 20 20", 57 "M 10 10 C 20 10 20 20 20 20", 58 "M 20 10 Q 20 20 30 20 L 10 20", // test double-back at y-max 59 }; 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); 64 check_direction(&path, SkPath::kCW_Direction, reporter); 65 } 66 67 static const char* gCCW[] = { 68 "M 10 10 L 10 10 Q 20 10 20 -20", 69 "M 10 10 C 20 10 20 -20 20 -20", 70 "M 20 10 Q 20 20 10 20 L 30 20", // test double-back at y-max 71 }; 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); 76 check_direction(&path, SkPath::kCCW_Direction, reporter); 77 } 78 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); 84 check_direction(&path, SkPath::kCW_Direction, reporter); 85 86 path.reset(); 87 path.addCircle(0, 0, SkIntToScalar(1), SkPath::kCW_Direction); 88 path.addCircle(0, 0, SkIntToScalar(2), SkPath::kCCW_Direction); 89 check_direction(&path, SkPath::kCCW_Direction, reporter); 90 91 #ifdef SK_SCALAR_IS_FLOAT 92 // triangle with one point really far from the origin. 93 path.reset(); 94 // the first point is roughly 1.05e10, 1.05e10 95 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 100 } 101 102 static 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 110 static void test_bounds(skiatest::Reporter* reporter) { 111 static const SkRect rects[] = { 112 { 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) }, 116 }; 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 127 static 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 143 static 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 163 static void check_close(skiatest::Reporter* reporter, const SkPath& path) { 164 for (int i = 0; i < 2; ++i) { 165 SkPath::Iter iter(path, (bool)i); 166 SkPoint mv; 167 SkPoint pts[4]; 168 SkPath::Verb v; 169 int nMT = 0; 170 int nCL = 0; 171 mv.set(0, 0); 172 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 192 static 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); 255 256 stroke_tiny_cubic(); 257 } 258 259 static 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 265 static void test_convexity2(skiatest::Reporter* reporter) { 266 SkPath pt; 267 pt.moveTo(0, 0); 268 pt.close(); 269 check_convexity(reporter, pt, SkPath::kConvex_Convexity); 270 271 SkPath line; 272 line.moveTo(12*SK_Scalar1, 20*SK_Scalar1); 273 line.lineTo(-12*SK_Scalar1, -20*SK_Scalar1); 274 line.close(); 275 check_convexity(reporter, pt, SkPath::kConvex_Convexity); 276 277 SkPath triLeft; 278 triLeft.moveTo(0, 0); 279 triLeft.lineTo(SK_Scalar1, 0); 280 triLeft.lineTo(SK_Scalar1, SK_Scalar1); 281 triLeft.close(); 282 check_convexity(reporter, triLeft, SkPath::kConvex_Convexity); 283 284 SkPath triRight; 285 triRight.moveTo(0, 0); 286 triRight.lineTo(-SK_Scalar1, 0); 287 triRight.lineTo(SK_Scalar1, SK_Scalar1); 288 triRight.close(); 289 check_convexity(reporter, triRight, SkPath::kConvex_Convexity); 290 291 SkPath square; 292 square.moveTo(0, 0); 293 square.lineTo(SK_Scalar1, 0); 294 square.lineTo(SK_Scalar1, SK_Scalar1); 295 square.lineTo(0, SK_Scalar1); 296 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); 303 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); 312 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); 319 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); 328 bowTie.close(); 329 check_convexity(reporter, bowTie, SkPath::kConcave_Convexity); 330 331 SkPath spiral; 332 spiral.moveTo(0, 0); 333 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); 339 spiral.close(); 340 check_convexity(reporter, spiral, SkPath::kConcave_Convexity); 341 342 SkPath dent; 343 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); 348 dent.close(); 349 check_convexity(reporter, dent, SkPath::kConcave_Convexity); 350 } 351 352 static 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); 356 357 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 367 static 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 386 static void test_convexity(skiatest::Reporter* reporter) { 387 static const SkPath::Convexity C = SkPath::kConcave_Convexity; 388 static const SkPath::Convexity V = SkPath::kConvex_Convexity; 389 390 SkPath path; 391 392 REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path)); 393 path.addCircle(0, 0, SkIntToScalar(10)); 394 REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path)); 395 path.addCircle(0, 0, SkIntToScalar(10)); // 2nd circle 396 REPORTER_ASSERT(reporter, C == SkPath::ComputeConvexity(path)); 397 path.reset(); 398 path.addRect(0, 0, SkIntToScalar(10), SkIntToScalar(10), SkPath::kCCW_Direction); 399 REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path)); 400 REPORTER_ASSERT(reporter, path.cheapIsDirection(SkPath::kCCW_Direction)); 401 path.reset(); 402 path.addRect(0, 0, SkIntToScalar(10), SkIntToScalar(10), SkPath::kCW_Direction); 403 REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path)); 404 REPORTER_ASSERT(reporter, path.cheapIsDirection(SkPath::kCW_Direction)); 405 406 static const struct { 407 const char* fPathStr; 408 SkPath::Convexity fExpectedConvexity; 409 } gRec[] = { 410 { "", SkPath::kConvex_Convexity }, 411 { "0 0", SkPath::kConvex_Convexity }, 412 { "0 0 10 10", SkPath::kConvex_Convexity }, 413 { "0 0 10 10 20 20 0 0 10 10", SkPath::kConcave_Convexity }, 414 { "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 428 // Simple isRect test is inline TestPath, below. 429 // test_isRect provides more extensive testing. 430 static void test_isRect(skiatest::Reporter* reporter) { 431 // passing tests (all moveTo / lineTo... 432 SkPoint r1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}}; 433 SkPoint r2[] = {{1, 0}, {1, 1}, {0, 1}, {0, 0}}; 434 SkPoint r3[] = {{1, 1}, {0, 1}, {0, 0}, {1, 0}}; 435 SkPoint r4[] = {{0, 1}, {0, 0}, {1, 0}, {1, 1}}; 436 SkPoint r5[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}}; 437 SkPoint r6[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}}; 438 SkPoint r7[] = {{1, 1}, {1, 0}, {0, 0}, {0, 1}}; 439 SkPoint r8[] = {{1, 0}, {0, 0}, {0, 1}, {1, 1}}; 440 SkPoint r9[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}}; 441 SkPoint ra[] = {{0, 0}, {0, .5f}, {0, 1}, {.5f, 1}, {1, 1}, {1, .5f}, 442 {1, 0}, {.5f, 0}}; 443 SkPoint rb[] = {{0, 0}, {.5f, 0}, {1, 0}, {1, .5f}, {1, 1}, {.5f, 1}, 444 {0, 1}, {0, .5f}}; 445 SkPoint rc[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}}; 446 SkPoint rd[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}}; 447 SkPoint re[] = {{0, 0}, {1, 0}, {1, 0}, {1, 1}, {0, 1}}; 448 449 // failing tests 450 SkPoint f1[] = {{0, 0}, {1, 0}, {1, 1}}; // too few points 451 SkPoint f2[] = {{0, 0}, {1, 1}, {0, 1}, {1, 0}}; // diagonal 452 SkPoint f3[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}, {1, 0}}; // wraps 453 SkPoint f4[] = {{0, 0}, {1, 0}, {0, 0}, {1, 0}, {1, 1}, {0, 1}}; // backs up 454 SkPoint f5[] = {{0, 0}, {1, 0}, {1, 1}, {2, 0}}; // end overshoots 455 SkPoint f6[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 2}}; // end overshoots 456 SkPoint f7[] = {{0, 0}, {1, 0}, {1, 1}, {0, 2}}; // end overshoots 457 SkPoint f8[] = {{0, 0}, {1, 0}, {1, 1}, {1, 0}}; // 'L' 458 459 // failing, no close 460 SkPoint c1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}}; // close doesn't match 461 SkPoint c2[] = {{0, 0}, {1, 0}, {1, 2}, {0, 2}, {0, 1}}; // ditto 462 463 size_t testLen[] = { 464 sizeof(r1), sizeof(r2), sizeof(r3), sizeof(r4), sizeof(r5), sizeof(r6), 465 sizeof(r7), sizeof(r8), sizeof(r9), sizeof(ra), sizeof(rb), sizeof(rc), 466 sizeof(rd), sizeof(re), 467 sizeof(f1), sizeof(f2), sizeof(f3), sizeof(f4), sizeof(f5), sizeof(f6), 468 sizeof(f7), sizeof(f8), 469 sizeof(c1), sizeof(c2) 470 }; 471 SkPoint* tests[] = { 472 r1, r2, r3, r4, r5, r6, r7, r8, r9, ra, rb, rc, rd, re, 473 f1, f2, f3, f4, f5, f6, f7, f8, 474 c1, c2 475 }; 476 SkPoint* lastPass = re; 477 SkPoint* lastClose = f8; 478 bool fail = false; 479 bool close = true; 480 const size_t testCount = sizeof(tests) / sizeof(tests[0]); 481 size_t index; 482 for (size_t testIndex = 0; testIndex < testCount; ++testIndex) { 483 SkPath path; 484 path.moveTo(tests[testIndex][0].fX, tests[testIndex][0].fY); 485 for (index = 1; index < testLen[testIndex] / sizeof(SkPoint); ++index) { 486 path.lineTo(tests[testIndex][index].fX, tests[testIndex][index].fY); 487 } 488 if (close) { 489 path.close(); 490 } 491 REPORTER_ASSERT(reporter, fail ^ path.isRect(0)); 492 if (tests[testIndex] == lastPass) { 493 fail = true; 494 } 495 if (tests[testIndex] == lastClose) { 496 close = false; 497 } 498 } 499 500 // fail, close then line 501 SkPath path1; 502 path1.moveTo(r1[0].fX, r1[0].fY); 503 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) { 504 path1.lineTo(r1[index].fX, r1[index].fY); 505 } 506 path1.close(); 507 path1.lineTo(1, 0); 508 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0)); 509 510 // fail, move in the middle 511 path1.reset(); 512 path1.moveTo(r1[0].fX, r1[0].fY); 513 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) { 514 if (index == 2) { 515 path1.moveTo(1, .5f); 516 } 517 path1.lineTo(r1[index].fX, r1[index].fY); 518 } 519 path1.close(); 520 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0)); 521 522 // fail, move on the edge 523 path1.reset(); 524 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) { 525 path1.moveTo(r1[index - 1].fX, r1[index - 1].fY); 526 path1.lineTo(r1[index].fX, r1[index].fY); 527 } 528 path1.close(); 529 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0)); 530 531 // fail, quad 532 path1.reset(); 533 path1.moveTo(r1[0].fX, r1[0].fY); 534 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) { 535 if (index == 2) { 536 path1.quadTo(1, .5f, 1, .5f); 537 } 538 path1.lineTo(r1[index].fX, r1[index].fY); 539 } 540 path1.close(); 541 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0)); 542 543 // fail, cubic 544 path1.reset(); 545 path1.moveTo(r1[0].fX, r1[0].fY); 546 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) { 547 if (index == 2) { 548 path1.cubicTo(1, .5f, 1, .5f, 1, .5f); 549 } 550 path1.lineTo(r1[index].fX, r1[index].fY); 551 } 552 path1.close(); 553 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0)); 554 } 555 556 static void test_flattening(skiatest::Reporter* reporter) { 557 SkPath p; 558 559 static const SkPoint pts[] = { 560 { 0, 0 }, 561 { SkIntToScalar(10), SkIntToScalar(10) }, 562 { SkIntToScalar(20), SkIntToScalar(10) }, { SkIntToScalar(20), 0 }, 563 { 0, 0 }, { 0, SkIntToScalar(10) }, { SkIntToScalar(1), SkIntToScalar(10) } 564 }; 565 p.moveTo(pts[0]); 566 p.lineTo(pts[1]); 567 p.quadTo(pts[2], pts[3]); 568 p.cubicTo(pts[4], pts[5], pts[6]); 569 570 SkWriter32 writer(100); 571 p.flatten(writer); 572 size_t size = writer.size(); 573 SkAutoMalloc storage(size); 574 writer.flatten(storage.get()); 575 SkReader32 reader(storage.get(), size); 576 577 SkPath p1; 578 REPORTER_ASSERT(reporter, p1 != p); 579 p1.unflatten(reader); 580 REPORTER_ASSERT(reporter, p1 == p); 581 } 582 583 static void test_transform(skiatest::Reporter* reporter) { 584 SkPath p, p1; 585 586 static const SkPoint pts[] = { 587 { 0, 0 }, 588 { SkIntToScalar(10), SkIntToScalar(10) }, 589 { SkIntToScalar(20), SkIntToScalar(10) }, { SkIntToScalar(20), 0 }, 590 { 0, 0 }, { 0, SkIntToScalar(10) }, { SkIntToScalar(1), SkIntToScalar(10) } 591 }; 592 p.moveTo(pts[0]); 593 p.lineTo(pts[1]); 594 p.quadTo(pts[2], pts[3]); 595 p.cubicTo(pts[4], pts[5], pts[6]); 596 597 SkMatrix matrix; 598 matrix.reset(); 599 p.transform(matrix, &p1); 600 REPORTER_ASSERT(reporter, p == p1); 601 602 matrix.setScale(SK_Scalar1 * 2, SK_Scalar1 * 3); 603 p.transform(matrix, &p1); 604 SkPoint pts1[7]; 605 int count = p1.getPoints(pts1, 7); 606 REPORTER_ASSERT(reporter, 7 == count); 607 for (int i = 0; i < count; ++i) { 608 SkPoint newPt = SkPoint::Make(pts[i].fX * 2, pts[i].fY * 3); 609 REPORTER_ASSERT(reporter, newPt == pts1[i]); 610 } 611 } 612 613 static void test_zero_length_paths(skiatest::Reporter* reporter) { 614 SkPath p; 615 SkPoint pt; 616 SkRect bounds; 617 618 // Lone moveTo case 619 p.moveTo(SK_Scalar1, SK_Scalar1); 620 REPORTER_ASSERT(reporter, !p.isEmpty()); 621 REPORTER_ASSERT(reporter, 1 == p.countPoints()); 622 p.getLastPt(&pt); 623 REPORTER_ASSERT(reporter, pt.fX == SK_Scalar1); 624 REPORTER_ASSERT(reporter, pt.fY == SK_Scalar1); 625 bounds.set(0, 0, 0, 0); 626 REPORTER_ASSERT(reporter, bounds == p.getBounds()); 627 628 // MoveTo-MoveTo case 629 p.moveTo(SK_Scalar1*2, SK_Scalar1); 630 REPORTER_ASSERT(reporter, !p.isEmpty()); 631 REPORTER_ASSERT(reporter, 2 == p.countPoints()); 632 p.getLastPt(&pt); 633 REPORTER_ASSERT(reporter, pt.fX == SK_Scalar1*2); 634 REPORTER_ASSERT(reporter, pt.fY == SK_Scalar1); 635 bounds.set(SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1); 636 REPORTER_ASSERT(reporter, bounds == p.getBounds()); 637 638 // moveTo-close case 639 p.reset(); 640 p.moveTo(SK_Scalar1, SK_Scalar1); 641 p.close(); 642 bounds.set(0, 0, 0, 0); 643 REPORTER_ASSERT(reporter, !p.isEmpty()); 644 REPORTER_ASSERT(reporter, 1 == p.countPoints()); 645 REPORTER_ASSERT(reporter, bounds == p.getBounds()); 646 647 // moveTo-close-moveTo-close case 648 p.moveTo(SK_Scalar1*2, SK_Scalar1); 649 p.close(); 650 bounds.set(SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1); 651 REPORTER_ASSERT(reporter, !p.isEmpty()); 652 REPORTER_ASSERT(reporter, 2 == p.countPoints()); 653 REPORTER_ASSERT(reporter, bounds == p.getBounds()); 654 655 // moveTo-line case 656 p.reset(); 657 p.moveTo(SK_Scalar1, SK_Scalar1); 658 p.lineTo(SK_Scalar1, SK_Scalar1); 659 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1); 660 REPORTER_ASSERT(reporter, !p.isEmpty()); 661 REPORTER_ASSERT(reporter, 2 == p.countPoints()); 662 REPORTER_ASSERT(reporter, bounds == p.getBounds()); 663 664 // moveTo-lineTo-moveTo-lineTo case 665 p.moveTo(SK_Scalar1*2, SK_Scalar1); 666 p.lineTo(SK_Scalar1*2, SK_Scalar1); 667 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1); 668 REPORTER_ASSERT(reporter, !p.isEmpty()); 669 REPORTER_ASSERT(reporter, 4 == p.countPoints()); 670 REPORTER_ASSERT(reporter, bounds == p.getBounds()); 671 672 // moveTo-line-close case 673 p.reset(); 674 p.moveTo(SK_Scalar1, SK_Scalar1); 675 p.lineTo(SK_Scalar1, SK_Scalar1); 676 p.close(); 677 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1); 678 REPORTER_ASSERT(reporter, !p.isEmpty()); 679 REPORTER_ASSERT(reporter, 2 == p.countPoints()); 680 REPORTER_ASSERT(reporter, bounds == p.getBounds()); 681 682 // moveTo-line-close-moveTo-line-close case 683 p.moveTo(SK_Scalar1*2, SK_Scalar1); 684 p.lineTo(SK_Scalar1*2, SK_Scalar1); 685 p.close(); 686 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1); 687 REPORTER_ASSERT(reporter, !p.isEmpty()); 688 REPORTER_ASSERT(reporter, 4 == p.countPoints()); 689 REPORTER_ASSERT(reporter, bounds == p.getBounds()); 690 691 // moveTo-quadTo case 692 p.reset(); 693 p.moveTo(SK_Scalar1, SK_Scalar1); 694 p.quadTo(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1); 695 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1); 696 REPORTER_ASSERT(reporter, !p.isEmpty()); 697 REPORTER_ASSERT(reporter, 3 == p.countPoints()); 698 REPORTER_ASSERT(reporter, bounds == p.getBounds()); 699 700 // moveTo-quadTo-close case 701 p.close(); 702 REPORTER_ASSERT(reporter, !p.isEmpty()); 703 REPORTER_ASSERT(reporter, 3 == p.countPoints()); 704 REPORTER_ASSERT(reporter, bounds == p.getBounds()); 705 706 // moveTo-quadTo-moveTo-quadTo case 707 p.reset(); 708 p.moveTo(SK_Scalar1, SK_Scalar1); 709 p.quadTo(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1); 710 p.moveTo(SK_Scalar1*2, SK_Scalar1); 711 p.quadTo(SK_Scalar1*2, SK_Scalar1, SK_Scalar1*2, SK_Scalar1); 712 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1); 713 REPORTER_ASSERT(reporter, !p.isEmpty()); 714 REPORTER_ASSERT(reporter, 6 == p.countPoints()); 715 REPORTER_ASSERT(reporter, bounds == p.getBounds()); 716 717 // moveTo-cubicTo case 718 p.reset(); 719 p.moveTo(SK_Scalar1, SK_Scalar1); 720 p.cubicTo(SK_Scalar1, SK_Scalar1, 721 SK_Scalar1, SK_Scalar1, 722 SK_Scalar1, SK_Scalar1); 723 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1); 724 REPORTER_ASSERT(reporter, !p.isEmpty()); 725 REPORTER_ASSERT(reporter, 4 == p.countPoints()); 726 REPORTER_ASSERT(reporter, bounds == p.getBounds()); 727 728 // moveTo-quadTo-close case 729 p.close(); 730 REPORTER_ASSERT(reporter, !p.isEmpty()); 731 REPORTER_ASSERT(reporter, 4 == p.countPoints()); 732 REPORTER_ASSERT(reporter, bounds == p.getBounds()); 733 734 // moveTo-quadTo-moveTo-quadTo case 735 p.reset(); 736 p.moveTo(SK_Scalar1, SK_Scalar1); 737 p.cubicTo(SK_Scalar1, SK_Scalar1, 738 SK_Scalar1, SK_Scalar1, 739 SK_Scalar1, SK_Scalar1); 740 p.moveTo(SK_Scalar1*2, SK_Scalar1); 741 p.cubicTo(SK_Scalar1*2, SK_Scalar1, 742 SK_Scalar1*2, SK_Scalar1, 743 SK_Scalar1*2, SK_Scalar1); 744 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1); 745 REPORTER_ASSERT(reporter, !p.isEmpty()); 746 REPORTER_ASSERT(reporter, 8 == p.countPoints()); 747 REPORTER_ASSERT(reporter, bounds == p.getBounds()); 748 } 749 750 struct SegmentInfo { 751 SkPath fPath; 752 int fPointCount; 753 }; 754 755 #define kCurveSegmentMask (SkPath::kQuad_SegmentMask | SkPath::kCubic_SegmentMask) 756 757 static void test_segment_masks(skiatest::Reporter* reporter) { 758 SkPath p; 759 p.moveTo(0, 0); 760 p.quadTo(100, 100, 200, 200); 761 REPORTER_ASSERT(reporter, SkPath::kQuad_SegmentMask == p.getSegmentMasks()); 762 REPORTER_ASSERT(reporter, !p.isEmpty()); 763 p.cubicTo(100, 100, 200, 200, 300, 300); 764 REPORTER_ASSERT(reporter, kCurveSegmentMask == p.getSegmentMasks()); 765 REPORTER_ASSERT(reporter, !p.isEmpty()); 766 p.reset(); 767 p.moveTo(0, 0); 768 p.cubicTo(100, 100, 200, 200, 300, 300); 769 REPORTER_ASSERT(reporter, SkPath::kCubic_SegmentMask == p.getSegmentMasks()); 770 REPORTER_ASSERT(reporter, !p.isEmpty()); 771 } 772 773 static void test_iter(skiatest::Reporter* reporter) { 774 SkPath p; 775 SkPoint pts[4]; 776 777 // Test an iterator with no path 778 SkPath::Iter noPathIter; 779 REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb); 780 // Test that setting an empty path works 781 noPathIter.setPath(p, false); 782 REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb); 783 // Test that close path makes no difference for an empty path 784 noPathIter.setPath(p, true); 785 REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb); 786 787 // Test an iterator with an initial empty path 788 SkPath::Iter iter(p, false); 789 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb); 790 791 // Test that close path makes no difference 792 SkPath::Iter forceCloseIter(p, true); 793 REPORTER_ASSERT(reporter, forceCloseIter.next(pts) == SkPath::kDone_Verb); 794 795 // Test that a move-only path produces nothing when iterated. 796 p.moveTo(SK_Scalar1, 0); 797 iter.setPath(p, false); 798 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb); 799 800 // No matter how many moves we add, we should still get nothing back. 801 p.moveTo(SK_Scalar1*2, 0); 802 p.moveTo(SK_Scalar1*3, 0); 803 p.moveTo(SK_Scalar1*4, 0); 804 p.moveTo(SK_Scalar1*5, 0); 805 iter.setPath(p, false); 806 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb); 807 808 // Nor should force closing 809 forceCloseIter.setPath(p, true); 810 REPORTER_ASSERT(reporter, forceCloseIter.next(pts) == SkPath::kDone_Verb); 811 812 // Initial closes should be ignored 813 p.reset(); 814 p.close(); 815 iter.setPath(p, false); 816 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb); 817 // Even if force closed 818 forceCloseIter.setPath(p, true); 819 REPORTER_ASSERT(reporter, forceCloseIter.next(pts) == SkPath::kDone_Verb); 820 821 // Move/close sequences should also be ignored 822 p.reset(); 823 p.close(); 824 p.moveTo(SK_Scalar1, 0); 825 p.close(); 826 p.close(); 827 p.moveTo(SK_Scalar1*2, 0); 828 p.close(); 829 p.moveTo(SK_Scalar1*3, 0); 830 p.moveTo(SK_Scalar1*4, 0); 831 p.close(); 832 iter.setPath(p, false); 833 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb); 834 // Even if force closed 835 forceCloseIter.setPath(p, true); 836 REPORTER_ASSERT(reporter, forceCloseIter.next(pts) == SkPath::kDone_Verb); 837 838 // The GM degeneratesegments.cpp test is more extensive 839 } 840 841 static void test_raw_iter(skiatest::Reporter* reporter) { 842 SkPath p; 843 SkPoint pts[4]; 844 845 // Test an iterator with no path 846 SkPath::RawIter noPathIter; 847 REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb); 848 // Test that setting an empty path works 849 noPathIter.setPath(p); 850 REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb); 851 852 // Test an iterator with an initial empty path 853 SkPath::RawIter iter(p); 854 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb); 855 856 // Test that a move-only path returns the move. 857 p.moveTo(SK_Scalar1, 0); 858 iter.setPath(p); 859 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb); 860 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1); 861 REPORTER_ASSERT(reporter, pts[0].fY == 0); 862 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb); 863 864 // No matter how many moves we add, we should get them all back 865 p.moveTo(SK_Scalar1*2, SK_Scalar1); 866 p.moveTo(SK_Scalar1*3, SK_Scalar1*2); 867 iter.setPath(p); 868 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb); 869 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1); 870 REPORTER_ASSERT(reporter, pts[0].fY == 0); 871 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb); 872 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2); 873 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1); 874 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb); 875 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*3); 876 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*2); 877 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb); 878 879 // Initial close is never ever stored 880 p.reset(); 881 p.close(); 882 iter.setPath(p); 883 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb); 884 885 // Move/close sequences 886 p.reset(); 887 p.close(); // Not stored, no purpose 888 p.moveTo(SK_Scalar1, 0); 889 p.close(); 890 p.close(); // Not stored, no purpose 891 p.moveTo(SK_Scalar1*2, SK_Scalar1); 892 p.close(); 893 p.moveTo(SK_Scalar1*3, SK_Scalar1*2); 894 p.moveTo(SK_Scalar1*4, SK_Scalar1*3); 895 p.close(); 896 iter.setPath(p); 897 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb); 898 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1); 899 REPORTER_ASSERT(reporter, pts[0].fY == 0); 900 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kClose_Verb); 901 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1); 902 REPORTER_ASSERT(reporter, pts[0].fY == 0); 903 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb); 904 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2); 905 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1); 906 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kClose_Verb); 907 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2); 908 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1); 909 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb); 910 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*3); 911 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*2); 912 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb); 913 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*4); 914 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*3); 915 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kClose_Verb); 916 REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*4); 917 REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*3); 918 REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb); 919 920 // Generate random paths and verify 921 SkPoint randomPts[25]; 922 for (int i = 0; i < 5; ++i) { 923 for (int j = 0; j < 5; ++j) { 924 randomPts[i*5+j].set(SK_Scalar1*i, SK_Scalar1*j); 925 } 926 } 927 928 // Max of 10 segments, max 3 points per segment 929 SkRandom rand(9876543); 930 SkPoint expectedPts[31]; // May have leading moveTo 931 SkPath::Verb expectedVerbs[22]; // May have leading moveTo 932 SkPath::Verb nextVerb; 933 934 for (int i = 0; i < 500; ++i) { 935 p.reset(); 936 bool lastWasClose = true; 937 bool haveMoveTo = false; 938 SkPoint lastMoveToPt = { 0, 0 }; 939 int numPoints = 0; 940 int numVerbs = (rand.nextU() >> 16) % 10; 941 int numIterVerbs = 0; 942 for (int j = 0; j < numVerbs; ++j) { 943 do { 944 nextVerb = static_cast<SkPath::Verb>((rand.nextU() >> 16) % SkPath::kDone_Verb); 945 } while (lastWasClose && nextVerb == SkPath::kClose_Verb); 946 int numRequiredPts; 947 switch (nextVerb) { 948 case SkPath::kMove_Verb: 949 expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25]; 950 p.moveTo(expectedPts[numPoints]); 951 lastMoveToPt = expectedPts[numPoints]; 952 numPoints += 1; 953 lastWasClose = false; 954 haveMoveTo = true; 955 break; 956 case SkPath::kLine_Verb: 957 if (!haveMoveTo) { 958 expectedPts[numPoints++] = lastMoveToPt; 959 expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb; 960 haveMoveTo = true; 961 } 962 expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25]; 963 p.lineTo(expectedPts[numPoints]); 964 numPoints += 1; 965 lastWasClose = false; 966 break; 967 case SkPath::kQuad_Verb: 968 if (!haveMoveTo) { 969 expectedPts[numPoints++] = lastMoveToPt; 970 expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb; 971 haveMoveTo = true; 972 } 973 expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25]; 974 expectedPts[numPoints + 1] = randomPts[(rand.nextU() >> 16) % 25]; 975 p.quadTo(expectedPts[numPoints], expectedPts[numPoints + 1]); 976 numPoints += 2; 977 lastWasClose = false; 978 break; 979 case SkPath::kCubic_Verb: 980 if (!haveMoveTo) { 981 expectedPts[numPoints++] = lastMoveToPt; 982 expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb; 983 haveMoveTo = true; 984 } 985 expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25]; 986 expectedPts[numPoints + 1] = randomPts[(rand.nextU() >> 16) % 25]; 987 expectedPts[numPoints + 2] = randomPts[(rand.nextU() >> 16) % 25]; 988 p.cubicTo(expectedPts[numPoints], expectedPts[numPoints + 1], 989 expectedPts[numPoints + 2]); 990 numPoints += 3; 991 lastWasClose = false; 992 break; 993 case SkPath::kClose_Verb: 994 p.close(); 995 haveMoveTo = false; 996 lastWasClose = true; 997 break; 998 default:; 999 } 1000 expectedVerbs[numIterVerbs++] = nextVerb; 1001 } 1002 1003 iter.setPath(p); 1004 numVerbs = numIterVerbs; 1005 numIterVerbs = 0; 1006 int numIterPts = 0; 1007 SkPoint lastMoveTo; 1008 SkPoint lastPt; 1009 lastMoveTo.set(0, 0); 1010 lastPt.set(0, 0); 1011 while ((nextVerb = iter.next(pts)) != SkPath::kDone_Verb) { 1012 REPORTER_ASSERT(reporter, nextVerb == expectedVerbs[numIterVerbs]); 1013 numIterVerbs++; 1014 switch (nextVerb) { 1015 case SkPath::kMove_Verb: 1016 REPORTER_ASSERT(reporter, numIterPts < numPoints); 1017 REPORTER_ASSERT(reporter, pts[0] == expectedPts[numIterPts]); 1018 lastPt = lastMoveTo = pts[0]; 1019 numIterPts += 1; 1020 break; 1021 case SkPath::kLine_Verb: 1022 REPORTER_ASSERT(reporter, numIterPts < numPoints + 1); 1023 REPORTER_ASSERT(reporter, pts[0] == lastPt); 1024 REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]); 1025 lastPt = pts[1]; 1026 numIterPts += 1; 1027 break; 1028 case SkPath::kQuad_Verb: 1029 REPORTER_ASSERT(reporter, numIterPts < numPoints + 2); 1030 REPORTER_ASSERT(reporter, pts[0] == lastPt); 1031 REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]); 1032 REPORTER_ASSERT(reporter, pts[2] == expectedPts[numIterPts + 1]); 1033 lastPt = pts[2]; 1034 numIterPts += 2; 1035 break; 1036 case SkPath::kCubic_Verb: 1037 REPORTER_ASSERT(reporter, numIterPts < numPoints + 3); 1038 REPORTER_ASSERT(reporter, pts[0] == lastPt); 1039 REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]); 1040 REPORTER_ASSERT(reporter, pts[2] == expectedPts[numIterPts + 1]); 1041 REPORTER_ASSERT(reporter, pts[3] == expectedPts[numIterPts + 2]); 1042 lastPt = pts[3]; 1043 numIterPts += 3; 1044 break; 1045 case SkPath::kClose_Verb: 1046 REPORTER_ASSERT(reporter, pts[0] == lastMoveTo); 1047 lastPt = lastMoveTo; 1048 break; 1049 default:; 1050 } 1051 } 1052 REPORTER_ASSERT(reporter, numIterPts == numPoints); 1053 REPORTER_ASSERT(reporter, numIterVerbs == numVerbs); 1054 } 1055 } 1056 1057 void TestPath(skiatest::Reporter* reporter); 1058 void TestPath(skiatest::Reporter* reporter) { 1059 { 1060 SkSize size; 1061 size.fWidth = 3.4f; 1062 size.width(); 1063 size = SkSize::Make(3,4); 1064 SkISize isize = SkISize::Make(3,4); 1065 } 1066 1067 SkTSize<SkScalar>::Make(3,4); 1068 1069 SkPath p, p2; 1070 SkRect bounds, bounds2; 1071 1072 REPORTER_ASSERT(reporter, p.isEmpty()); 1073 REPORTER_ASSERT(reporter, 0 == p.countPoints()); 1074 REPORTER_ASSERT(reporter, 0 == p.getSegmentMasks()); 1075 REPORTER_ASSERT(reporter, p.isConvex()); 1076 REPORTER_ASSERT(reporter, p.getFillType() == SkPath::kWinding_FillType); 1077 REPORTER_ASSERT(reporter, !p.isInverseFillType()); 1078 REPORTER_ASSERT(reporter, p == p2); 1079 REPORTER_ASSERT(reporter, !(p != p2)); 1080 1081 REPORTER_ASSERT(reporter, p.getBounds().isEmpty()); 1082 1083 bounds.set(0, 0, SK_Scalar1, SK_Scalar1); 1084 1085 p.addRoundRect(bounds, SK_Scalar1, SK_Scalar1); 1086 check_convex_bounds(reporter, p, bounds); 1087 // we have quads or cubics 1088 REPORTER_ASSERT(reporter, p.getSegmentMasks() & kCurveSegmentMask); 1089 REPORTER_ASSERT(reporter, !p.isEmpty()); 1090 1091 p.reset(); 1092 REPORTER_ASSERT(reporter, 0 == p.getSegmentMasks()); 1093 REPORTER_ASSERT(reporter, p.isEmpty()); 1094 1095 p.addOval(bounds); 1096 check_convex_bounds(reporter, p, bounds); 1097 REPORTER_ASSERT(reporter, !p.isEmpty()); 1098 1099 p.reset(); 1100 p.addRect(bounds); 1101 check_convex_bounds(reporter, p, bounds); 1102 // we have only lines 1103 REPORTER_ASSERT(reporter, SkPath::kLine_SegmentMask == p.getSegmentMasks()); 1104 REPORTER_ASSERT(reporter, !p.isEmpty()); 1105 1106 REPORTER_ASSERT(reporter, p != p2); 1107 REPORTER_ASSERT(reporter, !(p == p2)); 1108 1109 // does getPoints return the right result 1110 REPORTER_ASSERT(reporter, p.getPoints(NULL, 5) == 4); 1111 SkPoint pts[4]; 1112 int count = p.getPoints(pts, 4); 1113 REPORTER_ASSERT(reporter, count == 4); 1114 bounds2.set(pts, 4); 1115 REPORTER_ASSERT(reporter, bounds == bounds2); 1116 1117 bounds.offset(SK_Scalar1*3, SK_Scalar1*4); 1118 p.offset(SK_Scalar1*3, SK_Scalar1*4); 1119 REPORTER_ASSERT(reporter, bounds == p.getBounds()); 1120 1121 REPORTER_ASSERT(reporter, p.isRect(NULL)); 1122 bounds2.setEmpty(); 1123 REPORTER_ASSERT(reporter, p.isRect(&bounds2)); 1124 REPORTER_ASSERT(reporter, bounds == bounds2); 1125 1126 // now force p to not be a rect 1127 bounds.set(0, 0, SK_Scalar1/2, SK_Scalar1/2); 1128 p.addRect(bounds); 1129 REPORTER_ASSERT(reporter, !p.isRect(NULL)); 1130 test_isRect(reporter); 1131 1132 test_zero_length_paths(reporter); 1133 test_direction(reporter); 1134 test_convexity(reporter); 1135 test_convexity2(reporter); 1136 test_close(reporter); 1137 test_segment_masks(reporter); 1138 test_flattening(reporter); 1139 test_transform(reporter); 1140 test_bounds(reporter); 1141 test_iter(reporter); 1142 test_raw_iter(reporter); 1143 } 1144 1145 #include "TestClassDef.h" 1146 DEFINE_TESTCLASS("Path", PathTestClass, TestPath) 1147