PathTest.cpp revision 4da06ab3351f2a96f9216d96106db33a77b19644
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 "SkReader32.h" 13#include "SkSize.h" 14#include "SkWriter32.h" 15 16static void add_rect(SkPath* path, const SkRect& r) { 17 path->moveTo(r.fLeft, r.fTop); 18 path->lineTo(r.fRight, r.fTop); 19 path->lineTo(r.fRight, r.fBottom); 20 path->lineTo(r.fLeft, r.fBottom); 21 path->close(); 22} 23 24static void test_bounds(skiatest::Reporter* reporter) { 25 static const SkRect rects[] = { 26 { SkIntToScalar(10), SkIntToScalar(160), SkIntToScalar(610), SkIntToScalar(160) }, 27 { SkIntToScalar(610), SkIntToScalar(160), SkIntToScalar(610), SkIntToScalar(199) }, 28 { SkIntToScalar(10), SkIntToScalar(198), SkIntToScalar(610), SkIntToScalar(199) }, 29 { SkIntToScalar(10), SkIntToScalar(160), SkIntToScalar(10), SkIntToScalar(199) }, 30 }; 31 32 SkPath path0, path1; 33 for (size_t i = 0; i < SK_ARRAY_COUNT(rects); ++i) { 34 path0.addRect(rects[i]); 35 add_rect(&path1, rects[i]); 36 } 37 38 REPORTER_ASSERT(reporter, path0.getBounds() == path1.getBounds()); 39} 40 41static void stroke_cubic(const SkPoint pts[4]) { 42 SkPath path; 43 path.moveTo(pts[0]); 44 path.cubicTo(pts[1], pts[2], pts[3]); 45 46 SkPaint paint; 47 paint.setStyle(SkPaint::kStroke_Style); 48 paint.setStrokeWidth(SK_Scalar1 * 2); 49 50 SkPath fill; 51 paint.getFillPath(path, &fill); 52} 53 54// just ensure this can run w/o any SkASSERTS firing in the debug build 55// we used to assert due to differences in how we determine a degenerate vector 56// but that was fixed with the introduction of SkPoint::CanNormalize 57static void stroke_tiny_cubic() { 58 SkPoint p0[] = { 59 { 372.0f, 92.0f }, 60 { 372.0f, 92.0f }, 61 { 372.0f, 92.0f }, 62 { 372.0f, 92.0f }, 63 }; 64 65 stroke_cubic(p0); 66 67 SkPoint p1[] = { 68 { 372.0f, 92.0f }, 69 { 372.0007f, 92.000755f }, 70 { 371.99927f, 92.003922f }, 71 { 371.99826f, 92.003899f }, 72 }; 73 74 stroke_cubic(p1); 75} 76 77static void check_close(skiatest::Reporter* reporter, const SkPath& path) { 78 for (int i = 0; i < 2; ++i) { 79 SkPath::Iter iter(path, (bool)i); 80 SkPoint mv; 81 SkPoint pts[4]; 82 SkPath::Verb v; 83 int nMT = 0; 84 int nCL = 0; 85 mv.set(0, 0); 86 while (SkPath::kDone_Verb != (v = iter.next(pts))) { 87 switch (v) { 88 case SkPath::kMove_Verb: 89 mv = pts[0]; 90 ++nMT; 91 break; 92 case SkPath::kClose_Verb: 93 REPORTER_ASSERT(reporter, mv == pts[0]); 94 ++nCL; 95 break; 96 default: 97 break; 98 } 99 } 100 // if we force a close on the interator we should have a close 101 // for every moveTo 102 REPORTER_ASSERT(reporter, !i || nMT == nCL); 103 } 104} 105 106static void test_close(skiatest::Reporter* reporter) { 107 SkPath closePt; 108 closePt.moveTo(0, 0); 109 closePt.close(); 110 check_close(reporter, closePt); 111 112 SkPath openPt; 113 openPt.moveTo(0, 0); 114 check_close(reporter, openPt); 115 116 SkPath empty; 117 check_close(reporter, empty); 118 empty.close(); 119 check_close(reporter, empty); 120 121 SkPath rect; 122 rect.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1); 123 check_close(reporter, rect); 124 rect.close(); 125 check_close(reporter, rect); 126 127 SkPath quad; 128 quad.quadTo(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1); 129 check_close(reporter, quad); 130 quad.close(); 131 check_close(reporter, quad); 132 133 SkPath cubic; 134 quad.cubicTo(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 135 10*SK_Scalar1, 20 * SK_Scalar1, 20*SK_Scalar1); 136 check_close(reporter, cubic); 137 cubic.close(); 138 check_close(reporter, cubic); 139 140 SkPath line; 141 line.moveTo(SK_Scalar1, SK_Scalar1); 142 line.lineTo(10 * SK_Scalar1, 10*SK_Scalar1); 143 check_close(reporter, line); 144 line.close(); 145 check_close(reporter, line); 146 147 SkPath rect2; 148 rect2.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1); 149 rect2.close(); 150 rect2.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1); 151 check_close(reporter, rect2); 152 rect2.close(); 153 check_close(reporter, rect2); 154 155 SkPath oval3; 156 oval3.addOval(SkRect::MakeWH(SK_Scalar1*100,SK_Scalar1*100)); 157 oval3.close(); 158 oval3.addOval(SkRect::MakeWH(SK_Scalar1*200,SK_Scalar1*200)); 159 check_close(reporter, oval3); 160 oval3.close(); 161 check_close(reporter, oval3); 162 163 SkPath moves; 164 moves.moveTo(SK_Scalar1, SK_Scalar1); 165 moves.moveTo(5 * SK_Scalar1, SK_Scalar1); 166 moves.moveTo(SK_Scalar1, 10 * SK_Scalar1); 167 moves.moveTo(10 *SK_Scalar1, SK_Scalar1); 168 check_close(reporter, moves); 169 170 stroke_tiny_cubic(); 171} 172 173static void check_convexity(skiatest::Reporter* reporter, const SkPath& path, 174 SkPath::Convexity expected) { 175 SkPath::Convexity c = SkPath::ComputeConvexity(path); 176 REPORTER_ASSERT(reporter, c == expected); 177} 178 179static void test_convexity2(skiatest::Reporter* reporter) { 180 SkPath pt; 181 pt.moveTo(0, 0); 182 pt.close(); 183 check_convexity(reporter, pt, SkPath::kConvex_Convexity); 184 185 SkPath line; 186 line.moveTo(12, 20); 187 line.lineTo(-12, -20); 188 line.close(); 189 check_convexity(reporter, pt, SkPath::kConvex_Convexity); 190 191 SkPath triLeft; 192 triLeft.moveTo(0, 0); 193 triLeft.lineTo(1, 0); 194 triLeft.lineTo(1, 1); 195 triLeft.close(); 196 check_convexity(reporter, triLeft, SkPath::kConvex_Convexity); 197 198 SkPath triRight; 199 triRight.moveTo(0, 0); 200 triRight.lineTo(-1, 0); 201 triRight.lineTo(1, 1); 202 triRight.close(); 203 check_convexity(reporter, triRight, SkPath::kConvex_Convexity); 204 205 SkPath square; 206 square.moveTo(0, 0); 207 square.lineTo(1, 0); 208 square.lineTo(1, 1); 209 square.lineTo(0, 1); 210 square.close(); 211 check_convexity(reporter, square, SkPath::kConvex_Convexity); 212 213 SkPath redundantSquare; 214 redundantSquare.moveTo(0, 0); 215 redundantSquare.lineTo(0, 0); 216 redundantSquare.lineTo(0, 0); 217 redundantSquare.lineTo(1, 0); 218 redundantSquare.lineTo(1, 0); 219 redundantSquare.lineTo(1, 0); 220 redundantSquare.lineTo(1, 1); 221 redundantSquare.lineTo(1, 1); 222 redundantSquare.lineTo(1, 1); 223 redundantSquare.lineTo(0, 1); 224 redundantSquare.lineTo(0, 1); 225 redundantSquare.lineTo(0, 1); 226 redundantSquare.close(); 227 check_convexity(reporter, redundantSquare, SkPath::kConvex_Convexity); 228 229 SkPath bowTie; 230 bowTie.moveTo(0, 0); 231 bowTie.lineTo(0, 0); 232 bowTie.lineTo(0, 0); 233 bowTie.lineTo(1, 1); 234 bowTie.lineTo(1, 1); 235 bowTie.lineTo(1, 1); 236 bowTie.lineTo(1, 0); 237 bowTie.lineTo(1, 0); 238 bowTie.lineTo(1, 0); 239 bowTie.lineTo(0, 1); 240 bowTie.lineTo(0, 1); 241 bowTie.lineTo(0, 1); 242 bowTie.close(); 243 check_convexity(reporter, bowTie, SkPath::kConcave_Convexity); 244 245 SkPath spiral; 246 spiral.moveTo(0, 0); 247 spiral.lineTo(100, 0); 248 spiral.lineTo(100, 100); 249 spiral.lineTo(0, 100); 250 spiral.lineTo(0, 50); 251 spiral.lineTo(50, 50); 252 spiral.lineTo(50, 75); 253 spiral.close(); 254 check_convexity(reporter, spiral, SkPath::kConcave_Convexity); 255 256 SkPath dent; 257 dent.moveTo(SkIntToScalar(0), SkIntToScalar(0)); 258 dent.lineTo(SkIntToScalar(100), SkIntToScalar(100)); 259 dent.lineTo(SkIntToScalar(0), SkIntToScalar(100)); 260 dent.lineTo(SkIntToScalar(-50), SkIntToScalar(200)); 261 dent.lineTo(SkIntToScalar(-200), SkIntToScalar(100)); 262 dent.close(); 263 check_convexity(reporter, dent, SkPath::kConcave_Convexity); 264} 265 266static void check_convex_bounds(skiatest::Reporter* reporter, const SkPath& p, 267 const SkRect& bounds) { 268 REPORTER_ASSERT(reporter, p.isConvex()); 269 REPORTER_ASSERT(reporter, p.getBounds() == bounds); 270 271 SkPath p2(p); 272 REPORTER_ASSERT(reporter, p2.isConvex()); 273 REPORTER_ASSERT(reporter, p2.getBounds() == bounds); 274 275 SkPath other; 276 other.swap(p2); 277 REPORTER_ASSERT(reporter, other.isConvex()); 278 REPORTER_ASSERT(reporter, other.getBounds() == bounds); 279} 280 281static void setFromString(SkPath* path, const char str[]) { 282 bool first = true; 283 while (str) { 284 SkScalar x, y; 285 str = SkParse::FindScalar(str, &x); 286 if (NULL == str) { 287 break; 288 } 289 str = SkParse::FindScalar(str, &y); 290 SkASSERT(str); 291 if (first) { 292 path->moveTo(x, y); 293 first = false; 294 } else { 295 path->lineTo(x, y); 296 } 297 } 298} 299 300static void test_convexity(skiatest::Reporter* reporter) { 301 static const SkPath::Convexity C = SkPath::kConcave_Convexity; 302 static const SkPath::Convexity V = SkPath::kConvex_Convexity; 303 304 SkPath path; 305 306 REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path)); 307 path.addCircle(0, 0, 10); 308 REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path)); 309 path.addCircle(0, 0, 10); // 2nd circle 310 REPORTER_ASSERT(reporter, C == SkPath::ComputeConvexity(path)); 311 path.reset(); 312 path.addRect(0, 0, 10, 10, SkPath::kCCW_Direction); 313 REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path)); 314 path.reset(); 315 path.addRect(0, 0, 10, 10, SkPath::kCW_Direction); 316 REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path)); 317 318 static const struct { 319 const char* fPathStr; 320 SkPath::Convexity fExpectedConvexity; 321 } gRec[] = { 322 { "", SkPath::kConvex_Convexity }, 323 { "0 0", SkPath::kConvex_Convexity }, 324 { "0 0 10 10", SkPath::kConvex_Convexity }, 325 { "0 0 10 10 20 20 0 0 10 10", SkPath::kConcave_Convexity }, 326 { "0 0 10 10 10 20", SkPath::kConvex_Convexity }, 327 { "0 0 10 10 10 0", SkPath::kConvex_Convexity }, 328 { "0 0 10 10 10 0 0 10", SkPath::kConcave_Convexity }, 329 { "0 0 10 0 0 10 -10 -10", SkPath::kConcave_Convexity }, 330 }; 331 332 for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) { 333 SkPath path; 334 setFromString(&path, gRec[i].fPathStr); 335 SkPath::Convexity c = SkPath::ComputeConvexity(path); 336 REPORTER_ASSERT(reporter, c == gRec[i].fExpectedConvexity); 337 } 338} 339 340// Simple isRect test is inline TestPath, below. 341// test_isRect provides more extensive testing. 342static void test_isRect(skiatest::Reporter* reporter) { 343 // passing tests (all moveTo / lineTo... 344 SkPoint r1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}}; 345 SkPoint r2[] = {{1, 0}, {1, 1}, {0, 1}, {0, 0}}; 346 SkPoint r3[] = {{1, 1}, {0, 1}, {0, 0}, {1, 0}}; 347 SkPoint r4[] = {{0, 1}, {0, 0}, {1, 0}, {1, 1}}; 348 SkPoint r5[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}}; 349 SkPoint r6[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}}; 350 SkPoint r7[] = {{1, 1}, {1, 0}, {0, 0}, {0, 1}}; 351 SkPoint r8[] = {{1, 0}, {0, 0}, {0, 1}, {1, 1}}; 352 SkPoint r9[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}}; 353 SkPoint ra[] = {{0, 0}, {0, .5f}, {0, 1}, {.5f, 1}, {1, 1}, {1, .5f}, 354 {1, 0}, {.5f, 0}}; 355 SkPoint rb[] = {{0, 0}, {.5f, 0}, {1, 0}, {1, .5f}, {1, 1}, {.5f, 1}, 356 {0, 1}, {0, .5f}}; 357 SkPoint rc[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}}; 358 SkPoint rd[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}}; 359 SkPoint re[] = {{0, 0}, {1, 0}, {1, 0}, {1, 1}, {0, 1}}; 360 361 // failing tests 362 SkPoint f1[] = {{0, 0}, {1, 0}, {1, 1}}; // too few points 363 SkPoint f2[] = {{0, 0}, {1, 1}, {0, 1}, {1, 0}}; // diagonal 364 SkPoint f3[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}, {1, 0}}; // wraps 365 SkPoint f4[] = {{0, 0}, {1, 0}, {0, 0}, {1, 0}, {1, 1}, {0, 1}}; // backs up 366 SkPoint f5[] = {{0, 0}, {1, 0}, {1, 1}, {2, 0}}; // end overshoots 367 SkPoint f6[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 2}}; // end overshoots 368 SkPoint f7[] = {{0, 0}, {1, 0}, {1, 1}, {0, 2}}; // end overshoots 369 SkPoint f8[] = {{0, 0}, {1, 0}, {1, 1}, {1, 0}}; // 'L' 370 371 // failing, no close 372 SkPoint c1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}}; // close doesn't match 373 SkPoint c2[] = {{0, 0}, {1, 0}, {1, 2}, {0, 2}, {0, 1}}; // ditto 374 375 size_t testLen[] = { 376 sizeof(r1), sizeof(r2), sizeof(r3), sizeof(r4), sizeof(r5), sizeof(r6), 377 sizeof(r7), sizeof(r8), sizeof(r9), sizeof(ra), sizeof(rb), sizeof(rc), 378 sizeof(rd), sizeof(re), 379 sizeof(f1), sizeof(f2), sizeof(f3), sizeof(f4), sizeof(f5), sizeof(f6), 380 sizeof(f7), sizeof(f8), 381 sizeof(c1), sizeof(c2) 382 }; 383 SkPoint* tests[] = { 384 r1, r2, r3, r4, r5, r6, r7, r8, r9, ra, rb, rc, rd, re, 385 f1, f2, f3, f4, f5, f6, f7, f8, 386 c1, c2 387 }; 388 SkPoint* lastPass = re; 389 SkPoint* lastClose = f8; 390 bool fail = false; 391 bool close = true; 392 const size_t testCount = sizeof(tests) / sizeof(tests[0]); 393 size_t index; 394 for (size_t testIndex = 0; testIndex < testCount; ++testIndex) { 395 SkPath path; 396 path.moveTo(tests[testIndex][0].fX, tests[testIndex][0].fY); 397 for (index = 1; index < testLen[testIndex] / sizeof(SkPoint); ++index) { 398 path.lineTo(tests[testIndex][index].fX, tests[testIndex][index].fY); 399 } 400 if (close) { 401 path.close(); 402 } 403 REPORTER_ASSERT(reporter, fail ^ path.isRect(0)); 404 if (tests[testIndex] == lastPass) { 405 fail = true; 406 } 407 if (tests[testIndex] == lastClose) { 408 close = false; 409 } 410 } 411 412 // fail, close then line 413 SkPath path1; 414 path1.moveTo(r1[0].fX, r1[0].fY); 415 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) { 416 path1.lineTo(r1[index].fX, r1[index].fY); 417 } 418 path1.close(); 419 path1.lineTo(1, 0); 420 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0)); 421 422 // fail, move in the middle 423 path1.reset(); 424 path1.moveTo(r1[0].fX, r1[0].fY); 425 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) { 426 if (index == 2) { 427 path1.moveTo(1, .5f); 428 } 429 path1.lineTo(r1[index].fX, r1[index].fY); 430 } 431 path1.close(); 432 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0)); 433 434 // fail, move on the edge 435 path1.reset(); 436 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) { 437 path1.moveTo(r1[index - 1].fX, r1[index - 1].fY); 438 path1.lineTo(r1[index].fX, r1[index].fY); 439 } 440 path1.close(); 441 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0)); 442 443 // fail, quad 444 path1.reset(); 445 path1.moveTo(r1[0].fX, r1[0].fY); 446 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) { 447 if (index == 2) { 448 path1.quadTo(1, .5f, 1, .5f); 449 } 450 path1.lineTo(r1[index].fX, r1[index].fY); 451 } 452 path1.close(); 453 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0)); 454 455 // fail, cubic 456 path1.reset(); 457 path1.moveTo(r1[0].fX, r1[0].fY); 458 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) { 459 if (index == 2) { 460 path1.cubicTo(1, .5f, 1, .5f, 1, .5f); 461 } 462 path1.lineTo(r1[index].fX, r1[index].fY); 463 } 464 path1.close(); 465 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0)); 466} 467 468static void test_flattening(skiatest::Reporter* reporter) { 469 SkPath p; 470 471 static const SkPoint pts[] = { 472 { 0, 0 }, 473 { SkIntToScalar(10), SkIntToScalar(10) }, 474 { SkIntToScalar(20), SkIntToScalar(10) }, { SkIntToScalar(20), 0 }, 475 { 0, 0 }, { 0, SkIntToScalar(10) }, { SkIntToScalar(1), SkIntToScalar(10) } 476 }; 477 p.moveTo(pts[0]); 478 p.lineTo(pts[1]); 479 p.quadTo(pts[2], pts[3]); 480 p.cubicTo(pts[4], pts[5], pts[6]); 481 482 SkWriter32 writer(100); 483 p.flatten(writer); 484 size_t size = writer.size(); 485 SkAutoMalloc storage(size); 486 writer.flatten(storage.get()); 487 SkReader32 reader(storage.get(), size); 488 489 SkPath p1; 490 REPORTER_ASSERT(reporter, p1 != p); 491 p1.unflatten(reader); 492 REPORTER_ASSERT(reporter, p1 == p); 493} 494 495static void test_transform(skiatest::Reporter* reporter) { 496 SkPath p, p1; 497 498 static const SkPoint pts[] = { 499 { 0, 0 }, 500 { SkIntToScalar(10), SkIntToScalar(10) }, 501 { SkIntToScalar(20), SkIntToScalar(10) }, { SkIntToScalar(20), 0 }, 502 { 0, 0 }, { 0, SkIntToScalar(10) }, { SkIntToScalar(1), SkIntToScalar(10) } 503 }; 504 p.moveTo(pts[0]); 505 p.lineTo(pts[1]); 506 p.quadTo(pts[2], pts[3]); 507 p.cubicTo(pts[4], pts[5], pts[6]); 508 509 SkMatrix matrix; 510 matrix.reset(); 511 p.transform(matrix, &p1); 512 REPORTER_ASSERT(reporter, p == p1); 513 514 matrix.setScale(SK_Scalar1 * 2, SK_Scalar1 * 3); 515 p.transform(matrix, &p1); 516 SkPoint pts1[7]; 517 int count = p1.getPoints(pts1, 7); 518 REPORTER_ASSERT(reporter, 7 == count); 519 for (int i = 0; i < count; ++i) { 520 SkPoint newPt = SkPoint::Make(pts[i].fX * 2, pts[i].fY * 3); 521 REPORTER_ASSERT(reporter, newPt == pts1[i]); 522 } 523} 524 525static void test_zero_length_paths(skiatest::Reporter* reporter) { 526 SkPath p; 527 SkRect bounds; 528 529 // Lone moveTo case 530 p.moveTo(SK_Scalar1, SK_Scalar1); 531 bounds.set(0, 0, 0, 0); 532 REPORTER_ASSERT(reporter, !p.isEmpty()); 533 REPORTER_ASSERT(reporter, 1 == p.countPoints()); 534 REPORTER_ASSERT(reporter, bounds == p.getBounds()); 535 536 // MoveTo-MoveTo case 537 p.moveTo(SK_Scalar1*2, SK_Scalar1); 538 bounds.set(1, 1, 2, 1); 539 REPORTER_ASSERT(reporter, !p.isEmpty()); 540 REPORTER_ASSERT(reporter, 2 == p.countPoints()); 541 REPORTER_ASSERT(reporter, bounds == p.getBounds()); 542 543 // moveTo-close case 544 p.reset(); 545 p.moveTo(SK_Scalar1, SK_Scalar1); 546 p.close(); 547 bounds.set(0, 0, 0, 0); 548 REPORTER_ASSERT(reporter, !p.isEmpty()); 549 REPORTER_ASSERT(reporter, 1 == p.countPoints()); 550 REPORTER_ASSERT(reporter, bounds == p.getBounds()); 551 552 // moveTo-close-moveTo-close case 553 p.moveTo(SK_Scalar1*2, SK_Scalar1); 554 p.close(); 555 bounds.set(1, 1, 2, 1); 556 REPORTER_ASSERT(reporter, !p.isEmpty()); 557 REPORTER_ASSERT(reporter, 2 == p.countPoints()); 558 REPORTER_ASSERT(reporter, bounds == p.getBounds()); 559 560 // moveTo-line case 561 p.reset(); 562 p.moveTo(SK_Scalar1, SK_Scalar1); 563 p.lineTo(SK_Scalar1, SK_Scalar1); 564 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1); 565 REPORTER_ASSERT(reporter, !p.isEmpty()); 566 REPORTER_ASSERT(reporter, 2 == p.countPoints()); 567 REPORTER_ASSERT(reporter, bounds == p.getBounds()); 568 569 // moveTo-lineTo-moveTo-lineTo case 570 p.moveTo(SK_Scalar1*2, SK_Scalar1); 571 p.lineTo(SK_Scalar1*2, SK_Scalar1); 572 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1); 573 REPORTER_ASSERT(reporter, !p.isEmpty()); 574 REPORTER_ASSERT(reporter, 4 == p.countPoints()); 575 REPORTER_ASSERT(reporter, bounds == p.getBounds()); 576 577 // moveTo-line-close case 578 p.reset(); 579 p.moveTo(SK_Scalar1, SK_Scalar1); 580 p.lineTo(SK_Scalar1, SK_Scalar1); 581 p.close(); 582 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1); 583 REPORTER_ASSERT(reporter, !p.isEmpty()); 584 REPORTER_ASSERT(reporter, 2 == p.countPoints()); 585 REPORTER_ASSERT(reporter, bounds == p.getBounds()); 586 587 // moveTo-line-close-moveTo-line-close case 588 p.moveTo(SK_Scalar1*2, SK_Scalar1); 589 p.lineTo(SK_Scalar1*2, SK_Scalar1); 590 p.close(); 591 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1); 592 REPORTER_ASSERT(reporter, !p.isEmpty()); 593 REPORTER_ASSERT(reporter, 4 == p.countPoints()); 594 REPORTER_ASSERT(reporter, bounds == p.getBounds()); 595 596 // moveTo-quadTo case 597 p.reset(); 598 p.moveTo(SK_Scalar1, SK_Scalar1); 599 p.quadTo(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1); 600 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1); 601 REPORTER_ASSERT(reporter, !p.isEmpty()); 602 REPORTER_ASSERT(reporter, 3 == p.countPoints()); 603 REPORTER_ASSERT(reporter, bounds == p.getBounds()); 604 605 // moveTo-quadTo-close case 606 p.close(); 607 REPORTER_ASSERT(reporter, !p.isEmpty()); 608 REPORTER_ASSERT(reporter, 3 == p.countPoints()); 609 REPORTER_ASSERT(reporter, bounds == p.getBounds()); 610 611 // moveTo-quadTo-moveTo-quadTo case 612 p.reset(); 613 p.moveTo(SK_Scalar1, SK_Scalar1); 614 p.quadTo(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1); 615 p.moveTo(SK_Scalar1*2, SK_Scalar1); 616 p.quadTo(SK_Scalar1*2, SK_Scalar1, SK_Scalar1*2, SK_Scalar1); 617 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1); 618 REPORTER_ASSERT(reporter, !p.isEmpty()); 619 REPORTER_ASSERT(reporter, 6 == p.countPoints()); 620 REPORTER_ASSERT(reporter, bounds == p.getBounds()); 621 622 // moveTo-cubicTo case 623 p.reset(); 624 p.moveTo(SK_Scalar1, SK_Scalar1); 625 p.cubicTo(SK_Scalar1, SK_Scalar1, 626 SK_Scalar1, SK_Scalar1, 627 SK_Scalar1, SK_Scalar1); 628 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, 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-quadTo-close case 634 p.close(); 635 REPORTER_ASSERT(reporter, !p.isEmpty()); 636 REPORTER_ASSERT(reporter, 4 == p.countPoints()); 637 REPORTER_ASSERT(reporter, bounds == p.getBounds()); 638 639 // moveTo-quadTo-moveTo-quadTo case 640 p.reset(); 641 p.moveTo(SK_Scalar1, SK_Scalar1); 642 p.cubicTo(SK_Scalar1, SK_Scalar1, 643 SK_Scalar1, SK_Scalar1, 644 SK_Scalar1, SK_Scalar1); 645 p.moveTo(SK_Scalar1*2, SK_Scalar1); 646 p.cubicTo(SK_Scalar1*2, SK_Scalar1, 647 SK_Scalar1*2, SK_Scalar1, 648 SK_Scalar1*2, SK_Scalar1); 649 bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1); 650 REPORTER_ASSERT(reporter, !p.isEmpty()); 651 REPORTER_ASSERT(reporter, 8 == p.countPoints()); 652 REPORTER_ASSERT(reporter, bounds == p.getBounds()); 653} 654 655struct SegmentInfo { 656 SkPath fPath; 657 int fPointCount; 658}; 659 660#define kCurveSegmentMask (SkPath::kQuad_SegmentMask | SkPath::kCubic_SegmentMask) 661 662void TestPath(skiatest::Reporter* reporter); 663void TestPath(skiatest::Reporter* reporter) { 664 { 665 SkSize size; 666 size.fWidth = 3.4f; 667 size.width(); 668 size = SkSize::Make(3,4); 669 SkISize isize = SkISize::Make(3,4); 670 } 671 672 SkTSize<SkScalar>::Make(3,4); 673 674 SkPath p, p2; 675 SkRect bounds, bounds2; 676 677 REPORTER_ASSERT(reporter, p.isEmpty()); 678 REPORTER_ASSERT(reporter, 0 == p.countPoints()); 679 REPORTER_ASSERT(reporter, 0 == p.getSegmentMasks()); 680 REPORTER_ASSERT(reporter, p.isConvex()); 681 REPORTER_ASSERT(reporter, p.getFillType() == SkPath::kWinding_FillType); 682 REPORTER_ASSERT(reporter, !p.isInverseFillType()); 683 REPORTER_ASSERT(reporter, p == p2); 684 REPORTER_ASSERT(reporter, !(p != p2)); 685 686 REPORTER_ASSERT(reporter, p.getBounds().isEmpty()); 687 688 bounds.set(0, 0, SK_Scalar1, SK_Scalar1); 689 690 p.addRoundRect(bounds, SK_Scalar1, SK_Scalar1); 691 check_convex_bounds(reporter, p, bounds); 692 // we have quads or cubics 693 REPORTER_ASSERT(reporter, p.getSegmentMasks() & kCurveSegmentMask); 694 REPORTER_ASSERT(reporter, !p.isEmpty()); 695 696 p.reset(); 697 REPORTER_ASSERT(reporter, 0 == p.getSegmentMasks()); 698 REPORTER_ASSERT(reporter, p.isEmpty()); 699 700 p.addOval(bounds); 701 check_convex_bounds(reporter, p, bounds); 702 REPORTER_ASSERT(reporter, !p.isEmpty()); 703 704 p.reset(); 705 p.addRect(bounds); 706 check_convex_bounds(reporter, p, bounds); 707 // we have only lines 708 REPORTER_ASSERT(reporter, SkPath::kLine_SegmentMask == p.getSegmentMasks()); 709 REPORTER_ASSERT(reporter, !p.isEmpty()); 710 711 REPORTER_ASSERT(reporter, p != p2); 712 REPORTER_ASSERT(reporter, !(p == p2)); 713 714 // does getPoints return the right result 715 REPORTER_ASSERT(reporter, p.getPoints(NULL, 5) == 4); 716 SkPoint pts[4]; 717 int count = p.getPoints(pts, 4); 718 REPORTER_ASSERT(reporter, count == 4); 719 bounds2.set(pts, 4); 720 REPORTER_ASSERT(reporter, bounds == bounds2); 721 722 bounds.offset(SK_Scalar1*3, SK_Scalar1*4); 723 p.offset(SK_Scalar1*3, SK_Scalar1*4); 724 REPORTER_ASSERT(reporter, bounds == p.getBounds()); 725 726 REPORTER_ASSERT(reporter, p.isRect(NULL)); 727 bounds2.setEmpty(); 728 REPORTER_ASSERT(reporter, p.isRect(&bounds2)); 729 REPORTER_ASSERT(reporter, bounds == bounds2); 730 731 // now force p to not be a rect 732 bounds.set(0, 0, SK_Scalar1/2, SK_Scalar1/2); 733 p.addRect(bounds); 734 REPORTER_ASSERT(reporter, !p.isRect(NULL)); 735 test_isRect(reporter); 736 737 SkPoint pt; 738 739 p.moveTo(SK_Scalar1, 0); 740 p.getLastPt(&pt); 741 REPORTER_ASSERT(reporter, pt.fX == SK_Scalar1); 742 REPORTER_ASSERT(reporter, !p.isEmpty()); 743 744 test_zero_length_paths(reporter); 745 test_convexity(reporter); 746 test_convexity2(reporter); 747 test_close(reporter); 748 749 p.reset(); 750 p.moveTo(0, 0); 751 p.quadTo(100, 100, 200, 200); 752 REPORTER_ASSERT(reporter, SkPath::kQuad_SegmentMask == p.getSegmentMasks()); 753 REPORTER_ASSERT(reporter, !p.isEmpty()); 754 p.cubicTo(100, 100, 200, 200, 300, 300); 755 REPORTER_ASSERT(reporter, kCurveSegmentMask == p.getSegmentMasks()); 756 REPORTER_ASSERT(reporter, !p.isEmpty()); 757 p.reset(); 758 p.moveTo(0, 0); 759 p.cubicTo(100, 100, 200, 200, 300, 300); 760 REPORTER_ASSERT(reporter, SkPath::kCubic_SegmentMask == p.getSegmentMasks()); 761 REPORTER_ASSERT(reporter, !p.isEmpty()); 762 763 test_flattening(reporter); 764 test_transform(reporter); 765 test_bounds(reporter); 766} 767 768#include "TestClassDef.h" 769DEFINE_TESTCLASS("Path", PathTestClass, TestPath) 770