1 /* 2 * Copyright 2011 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "gm.h" 9 #include "SkPath.h" 10 11 typedef SkScalar (*MakePathProc)(SkPath*); 12 13 static SkScalar make_frame(SkPath* path) { 14 SkRect r = { SkIntToScalar(10), SkIntToScalar(10), 15 SkIntToScalar(630), SkIntToScalar(470) }; 16 path->addRoundRect(r, SkIntToScalar(15), SkIntToScalar(15)); 17 18 SkPaint paint; 19 paint.setStyle(SkPaint::kStroke_Style); 20 paint.setStrokeWidth(SkIntToScalar(5)); 21 paint.getFillPath(*path, path); 22 return SkIntToScalar(15); 23 } 24 25 static SkScalar make_triangle(SkPath* path) { 26 constexpr int gCoord[] = { 27 10, 20, 15, 5, 30, 30 28 }; 29 path->moveTo(SkIntToScalar(gCoord[0]), SkIntToScalar(gCoord[1])); 30 path->lineTo(SkIntToScalar(gCoord[2]), SkIntToScalar(gCoord[3])); 31 path->lineTo(SkIntToScalar(gCoord[4]), SkIntToScalar(gCoord[5])); 32 path->close(); 33 path->offset(SkIntToScalar(10), SkIntToScalar(0)); 34 return SkIntToScalar(30); 35 } 36 37 static SkScalar make_rect(SkPath* path) { 38 SkRect r = { SkIntToScalar(10), SkIntToScalar(10), 39 SkIntToScalar(30), SkIntToScalar(30) }; 40 path->addRect(r); 41 path->offset(SkIntToScalar(10), SkIntToScalar(0)); 42 return SkIntToScalar(30); 43 } 44 45 static SkScalar make_oval(SkPath* path) { 46 SkRect r = { SkIntToScalar(10), SkIntToScalar(10), 47 SkIntToScalar(30), SkIntToScalar(30) }; 48 path->addOval(r); 49 path->offset(SkIntToScalar(10), SkIntToScalar(0)); 50 return SkIntToScalar(30); 51 } 52 53 static SkScalar make_sawtooth(SkPath* path, int teeth) { 54 SkScalar x = SkIntToScalar(20); 55 SkScalar y = SkIntToScalar(20); 56 const SkScalar x0 = x; 57 const SkScalar dx = SkIntToScalar(5); 58 const SkScalar dy = SkIntToScalar(10); 59 60 path->moveTo(x, y); 61 for (int i = 0; i < teeth; i++) { 62 x += dx; 63 path->lineTo(x, y - dy); 64 x += dx; 65 path->lineTo(x, y + dy); 66 } 67 path->lineTo(x, y + (2 * dy)); 68 path->lineTo(x0, y + (2 * dy)); 69 path->close(); 70 return SkIntToScalar(30); 71 } 72 73 static SkScalar make_sawtooth_3(SkPath* path) { return make_sawtooth(path, 3); } 74 static SkScalar make_sawtooth_32(SkPath* path) { return make_sawtooth(path, 32); } 75 76 static SkScalar make_house(SkPath* path) { 77 path->moveTo(21, 23); 78 path->lineTo(21, 11.534f); 79 path->lineTo(22.327f, 12.741f); 80 path->lineTo(23.673f, 11.261f); 81 path->lineTo(12, 0.648f); 82 path->lineTo(8, 4.285f); 83 path->lineTo(8, 2); 84 path->lineTo(4, 2); 85 path->lineTo(4, 7.921f); 86 path->lineTo(0.327f, 11.26f); 87 path->lineTo(1.673f, 12.74f); 88 path->lineTo(3, 11.534f); 89 path->lineTo(3, 23); 90 path->lineTo(11, 23); 91 path->lineTo(11, 18); 92 path->lineTo(13, 18); 93 path->lineTo(13, 23); 94 path->lineTo(21, 23); 95 path->close(); 96 path->lineTo(9, 16); 97 path->lineTo(9, 21); 98 path->lineTo(5, 21); 99 path->lineTo(5, 9.715f); 100 path->lineTo(12, 3.351f); 101 path->lineTo(19, 9.715f); 102 path->lineTo(19, 21); 103 path->lineTo(15, 21); 104 path->lineTo(15, 16); 105 path->lineTo(9, 16); 106 path->close(); 107 path->offset(20, 0); 108 return SkIntToScalar(30); 109 } 110 111 static SkScalar make_star(SkPath* path, int n) { 112 const SkScalar c = SkIntToScalar(45); 113 const SkScalar r = SkIntToScalar(20); 114 115 SkScalar rad = -SK_ScalarPI / 2; 116 const SkScalar drad = (n >> 1) * SK_ScalarPI * 2 / n; 117 118 path->moveTo(c, c - r); 119 for (int i = 1; i < n; i++) { 120 rad += drad; 121 SkScalar cosV, sinV = SkScalarSinCos(rad, &cosV); 122 path->lineTo(c + cosV * r, c + sinV * r); 123 } 124 path->close(); 125 return r * 2 * 6 / 5; 126 } 127 128 static SkScalar make_star_5(SkPath* path) { return make_star(path, 5); } 129 static SkScalar make_star_13(SkPath* path) { return make_star(path, 13); } 130 131 // We don't expect any output from this path. 132 static SkScalar make_line(SkPath* path) { 133 path->moveTo(SkIntToScalar(30), SkIntToScalar(30)); 134 path->lineTo(SkIntToScalar(120), SkIntToScalar(40)); 135 path->close(); 136 path->moveTo(SkIntToScalar(150), SkIntToScalar(30)); 137 path->lineTo(SkIntToScalar(150), SkIntToScalar(30)); 138 path->lineTo(SkIntToScalar(300), SkIntToScalar(40)); 139 path->close(); 140 return SkIntToScalar(40); 141 } 142 143 static void make_info(SkPath* path) { 144 path->moveTo(24, 4); 145 path->cubicTo(12.94999980926514f, 146 4, 147 4, 148 12.94999980926514f, 149 4, 150 24); 151 path->cubicTo(4, 152 35.04999923706055f, 153 12.94999980926514f, 154 44, 155 24, 156 44); 157 path->cubicTo(35.04999923706055f, 158 44, 159 44, 160 35.04999923706055f, 161 44, 162 24); 163 path->cubicTo(44, 164 12.95000076293945f, 165 35.04999923706055f, 166 4, 167 24, 168 4); 169 path->close(); 170 path->moveTo(26, 34); 171 path->lineTo(22, 34); 172 path->lineTo(22, 22); 173 path->lineTo(26, 22); 174 path->lineTo(26, 34); 175 path->close(); 176 path->moveTo(26, 18); 177 path->lineTo(22, 18); 178 path->lineTo(22, 14); 179 path->lineTo(26, 14); 180 path->lineTo(26, 18); 181 path->close(); 182 } 183 184 static void make_accessibility(SkPath* path) { 185 path->moveTo(12, 2); 186 path->cubicTo(13.10000038146973f, 187 2, 188 14, 189 2.900000095367432f, 190 14, 191 4); 192 path->cubicTo(14, 193 5.099999904632568f, 194 13.10000038146973f, 195 6, 196 12, 197 6); 198 path->cubicTo(10.89999961853027f, 199 6, 200 10, 201 5.099999904632568f, 202 10, 203 4); 204 path->cubicTo(10, 205 2.900000095367432f, 206 10.89999961853027f, 207 2, 208 12, 209 2); 210 path->close(); 211 path->moveTo(21, 9); 212 path->lineTo(15, 9); 213 path->lineTo(15, 22); 214 path->lineTo(13, 22); 215 path->lineTo(13, 16); 216 path->lineTo(11, 16); 217 path->lineTo(11, 22); 218 path->lineTo(9, 22); 219 path->lineTo(9, 9); 220 path->lineTo(3, 9); 221 path->lineTo(3, 7); 222 path->lineTo(21, 7); 223 path->lineTo(21, 9); 224 path->close(); 225 } 226 227 // test case for http://crbug.com/695196 228 static void make_visualizer(SkPath* path) { 229 path->moveTo(1.9520f, 2.0000f); 230 path->conicTo(1.5573f, 1.9992f, 1.2782f, 2.2782f, 0.9235f); 231 path->conicTo(0.9992f, 2.5573f, 1.0000f, 2.9520f, 0.9235f); 232 path->lineTo(1.0000f, 5.4300f); 233 path->lineTo(17.0000f, 5.4300f); 234 path->lineTo(17.0000f, 2.9520f); 235 path->conicTo(17.0008f, 2.5573f, 16.7218f, 2.2782f, 0.9235f); 236 path->conicTo(16.4427f, 1.9992f, 16.0480f, 2.0000f, 0.9235f); 237 path->lineTo(1.9520f, 2.0000f); 238 path->close(); 239 path->moveTo(2.7140f, 3.1430f); 240 path->conicTo(3.0547f, 3.1287f, 3.2292f, 3.4216f, 0.8590f); 241 path->conicTo(3.4038f, 3.7145f, 3.2292f, 4.0074f, 0.8590f); 242 path->conicTo(3.0547f, 4.3003f, 2.7140f, 4.2860f, 0.8590f); 243 path->conicTo(2.1659f, 4.2631f, 2.1659f, 3.7145f, 0.7217f); 244 path->conicTo(2.1659f, 3.1659f, 2.7140f, 3.1430f, 0.7217f); 245 path->lineTo(2.7140f, 3.1430f); 246 path->close(); 247 path->moveTo(5.0000f, 3.1430f); 248 path->conicTo(5.3407f, 3.1287f, 5.5152f, 3.4216f, 0.8590f); 249 path->conicTo(5.6898f, 3.7145f, 5.5152f, 4.0074f, 0.8590f); 250 path->conicTo(5.3407f, 4.3003f, 5.0000f, 4.2860f, 0.8590f); 251 path->conicTo(4.4519f, 4.2631f, 4.4519f, 3.7145f, 0.7217f); 252 path->conicTo(4.4519f, 3.1659f, 5.0000f, 3.1430f, 0.7217f); 253 path->lineTo(5.0000f, 3.1430f); 254 path->close(); 255 path->moveTo(7.2860f, 3.1430f); 256 path->conicTo(7.6267f, 3.1287f, 7.8012f, 3.4216f, 0.8590f); 257 path->conicTo(7.9758f, 3.7145f, 7.8012f, 4.0074f, 0.8590f); 258 path->conicTo(7.6267f, 4.3003f, 7.2860f, 4.2860f, 0.8590f); 259 path->conicTo(6.7379f, 4.2631f, 6.7379f, 3.7145f, 0.7217f); 260 path->conicTo(6.7379f, 3.1659f, 7.2860f, 3.1430f, 0.7217f); 261 path->close(); 262 path->moveTo(1.0000f, 6.1900f); 263 path->lineTo(1.0000f, 14.3810f); 264 path->conicTo(0.9992f, 14.7757f, 1.2782f, 15.0548f, 0.9235f); 265 path->conicTo(1.5573f, 15.3338f, 1.9520f, 15.3330f, 0.9235f); 266 path->lineTo(16.0480f, 15.3330f); 267 path->conicTo(16.4427f, 15.3338f, 16.7218f, 15.0548f, 0.9235f); 268 path->conicTo(17.0008f, 14.7757f, 17.0000f, 14.3810f, 0.9235f); 269 path->lineTo(17.0000f, 6.1910f); 270 path->lineTo(1.0000f, 6.1910f); 271 path->lineTo(1.0000f, 6.1900f); 272 path->close(); 273 } 274 275 constexpr MakePathProc gProcs[] = { 276 make_frame, 277 make_triangle, 278 make_rect, 279 make_oval, 280 make_sawtooth_32, 281 make_star_5, 282 make_star_13, 283 make_line, 284 make_house, 285 make_sawtooth_3, 286 }; 287 288 #define N SK_ARRAY_COUNT(gProcs) 289 290 class PathFillGM : public skiagm::GM { 291 SkPath fPath[N]; 292 SkScalar fDY[N]; 293 SkPath fInfoPath; 294 SkPath fAccessibilityPath; 295 SkPath fVisualizerPath; 296 protected: 297 void onOnceBeforeDraw() override { 298 for (size_t i = 0; i < N; i++) { 299 fDY[i] = gProcs[i](&fPath[i]); 300 } 301 302 make_info(&fInfoPath); 303 make_accessibility(&fAccessibilityPath); 304 make_visualizer(&fVisualizerPath); 305 } 306 307 308 SkString onShortName() override { 309 return SkString("pathfill"); 310 } 311 312 SkISize onISize() override { 313 return SkISize::Make(640, 480); 314 } 315 316 void onDraw(SkCanvas* canvas) override { 317 SkPaint paint; 318 paint.setAntiAlias(true); 319 320 for (size_t i = 0; i < N; i++) { 321 canvas->drawPath(fPath[i], paint); 322 canvas->translate(SkIntToScalar(0), fDY[i]); 323 } 324 325 canvas->save(); 326 canvas->scale(0.300000011920929f, 0.300000011920929f); 327 canvas->translate(50, 50); 328 canvas->drawPath(fInfoPath, paint); 329 canvas->restore(); 330 331 canvas->scale(2, 2); 332 canvas->translate(5, 15); 333 canvas->drawPath(fAccessibilityPath, paint); 334 335 canvas->scale(0.5f, 0.5f); 336 canvas->translate(5, 50); 337 canvas->drawPath(fVisualizerPath, paint); 338 } 339 340 private: 341 typedef skiagm::GM INHERITED; 342 }; 343 344 // test inverse-fill w/ a clip that completely excludes the geometry 345 class PathInverseFillGM : public skiagm::GM { 346 SkPath fPath[N]; 347 SkScalar fDY[N]; 348 protected: 349 void onOnceBeforeDraw() override { 350 for (size_t i = 0; i < N; i++) { 351 fDY[i] = gProcs[i](&fPath[i]); 352 } 353 } 354 355 SkString onShortName() override { 356 return SkString("pathinvfill"); 357 } 358 359 SkISize onISize() override { 360 return SkISize::Make(450, 220); 361 } 362 363 static void show(SkCanvas* canvas, const SkPath& path, const SkPaint& paint, 364 const SkRect* clip, SkScalar top, const SkScalar bottom) { 365 canvas->save(); 366 if (clip) { 367 SkRect r = *clip; 368 r.fTop = top; 369 r.fBottom = bottom; 370 canvas->clipRect(r); 371 } 372 canvas->drawPath(path, paint); 373 canvas->restore(); 374 } 375 376 void onDraw(SkCanvas* canvas) override { 377 SkPath path; 378 379 path.addCircle(SkIntToScalar(50), SkIntToScalar(50), SkIntToScalar(40)); 380 path.toggleInverseFillType(); 381 382 SkRect clipR = { 0, 0, SkIntToScalar(100), SkIntToScalar(200) }; 383 384 canvas->translate(SkIntToScalar(10), SkIntToScalar(10)); 385 386 for (int doclip = 0; doclip <= 1; ++doclip) { 387 for (int aa = 0; aa <= 1; ++aa) { 388 SkPaint paint; 389 paint.setAntiAlias(SkToBool(aa)); 390 391 canvas->save(); 392 canvas->clipRect(clipR); 393 394 const SkRect* clipPtr = doclip ? &clipR : nullptr; 395 396 show(canvas, path, paint, clipPtr, clipR.fTop, clipR.centerY()); 397 show(canvas, path, paint, clipPtr, clipR.centerY(), clipR.fBottom); 398 399 canvas->restore(); 400 canvas->translate(SkIntToScalar(110), 0); 401 } 402 } 403 } 404 405 private: 406 typedef skiagm::GM INHERITED; 407 }; 408 409 DEF_SIMPLE_GM(rotatedcubicpath, canvas, 200, 200) { 410 SkPaint p; 411 p.setAntiAlias(true); 412 p.setStyle(SkPaint::kFill_Style); 413 414 canvas->translate(50, 50); 415 SkPath path; 416 path.moveTo(48,-23); 417 path.cubicTo(48,-29.5, 6,-30, 6,-30); 418 path.cubicTo(6,-30, 2,0, 2,0); 419 path.cubicTo(2,0, 44,-21.5, 48,-23); 420 path.close(); 421 422 p.setColor(SK_ColorBLUE); 423 canvas->drawPath(path, p); 424 425 // Rotated path, which is not antialiased on GPU 426 p.setColor(SK_ColorRED); 427 canvas->rotate(90); 428 canvas->drawPath(path, p); 429 } 430 431 /////////////////////////////////////////////////////////////////////////////// 432 433 DEF_GM( return new PathFillGM; ) 434 DEF_GM( return new PathInverseFillGM; ) 435 436 DEF_SIMPLE_GM(bug7792, canvas, 800, 800) { 437 // from skbug.com/7792 bug description 438 SkPaint p; 439 SkPath path; 440 path.moveTo(10, 10); 441 path.moveTo(75, 75); 442 path.lineTo(150, 75); 443 path.lineTo(150, 150); 444 path.lineTo(75, 150); 445 canvas->drawPath(path, p); 446 // from skbug.com/7792#c3 447 canvas->translate(200, 0); 448 path.reset(); 449 path.moveTo(75, 50); 450 path.moveTo(100, 75); 451 path.lineTo(150, 75); 452 path.lineTo(150, 150); 453 path.lineTo(75, 150); 454 path.lineTo(75, 50); 455 path.close(); 456 canvas->drawPath(path, p); 457 // from skbug.com/7792#c9 458 canvas->translate(200, 0); 459 path.reset(); 460 path.moveTo(10, 10); 461 path.moveTo(75, 75); 462 path.lineTo(150, 75); 463 path.lineTo(150, 150); 464 path.lineTo(75, 150); 465 path.close(); 466 canvas->drawPath(path, p); 467 // from skbug.com/7792#c11 468 canvas->translate(-200 * 2, 200); 469 path.reset(); 470 path.moveTo(75, 150); 471 path.lineTo(75, 75); 472 path.lineTo(150, 75); 473 path.lineTo(150, 150); 474 path.lineTo(75, 150); 475 path.moveTo(75, 150); 476 canvas->drawPath(path, p); 477 // from skbug.com/7792#c14 478 canvas->translate(200, 0); 479 path.reset(); 480 path.moveTo(250, 75); 481 path.moveTo(250, 75); 482 path.moveTo(250, 75); 483 path.moveTo(100, 75); 484 path.lineTo(150, 75); 485 path.lineTo(150, 150); 486 path.lineTo(75, 150); 487 path.lineTo(75, 75); 488 path.close(); 489 path.lineTo(0, 0); 490 path.close(); 491 canvas->drawPath(path, p); 492 // from skbug.com/7792#c15 493 canvas->translate(200, 0); 494 path.reset(); 495 path.moveTo(75, 75); 496 path.lineTo(150, 75); 497 path.lineTo(150, 150); 498 path.lineTo(75, 150); 499 path.moveTo(250, 75); 500 canvas->drawPath(path, p); 501 // from skbug.com/7792#c17 502 canvas->translate(-200 * 2, 200); 503 path.reset(); 504 path.moveTo(75, 10); 505 path.moveTo(75, 75); 506 path.lineTo(150, 75); 507 path.lineTo(150, 150); 508 path.lineTo(75, 150); 509 path.lineTo(75, 10); 510 path.close(); 511 canvas->drawPath(path, p); 512 // from skbug.com/7792#c19 513 canvas->translate(200, 0); 514 path.reset(); 515 path.moveTo(75, 75); 516 path.lineTo(75, 75); 517 path.lineTo(75, 75); 518 path.lineTo(75, 75); 519 path.lineTo(150, 75); 520 path.lineTo(150, 150); 521 path.lineTo(75, 150); 522 path.close(); 523 path.moveTo(10, 10); 524 path.lineTo(30, 10); 525 path.lineTo(10, 30); 526 canvas->drawPath(path, p); 527 // from skbug.com/7792#c23 528 canvas->translate(200, 0); 529 path.reset(); 530 path.moveTo(75, 75); 531 path.lineTo(75, 75); 532 path.moveTo(75, 75); 533 path.lineTo(75, 75); 534 path.lineTo(150, 75); 535 path.lineTo(150, 150); 536 path.lineTo(75, 150); 537 path.close(); 538 canvas->drawPath(path, p); 539 // from skbug.com/7792#c29 540 canvas->translate(-200 * 2, 200); 541 path.reset(); 542 path.moveTo(75, 75); 543 path.lineTo(150, 75); 544 path.lineTo(150, 150); 545 path.lineTo(75, 150); 546 path.lineTo(75, 250); 547 path.moveTo(75, 75); 548 path.close(); 549 canvas->drawPath(path, p); 550 // from skbug.com/7792#c31 551 canvas->translate(200, 0); 552 path.reset(); 553 path.moveTo(75, 75); 554 path.lineTo(150, 75); 555 path.lineTo(150, 150); 556 path.lineTo(75, 150); 557 path.lineTo(75, 10); 558 path.moveTo(75, 75); 559 path.close(); 560 canvas->drawPath(path, p); 561 // from skbug.com/7792#c36 562 canvas->translate(200, 0); 563 path.reset(); 564 path.moveTo(75, 75); 565 path.lineTo(150, 75); 566 path.lineTo(150, 150); 567 path.lineTo(10, 150); 568 path.moveTo(75, 75); 569 path.lineTo(75, 75); 570 canvas->drawPath(path, p); 571 // from skbug.com/7792#c39 572 canvas->translate(200, -200 * 3); 573 path.reset(); 574 path.moveTo(150, 75); 575 path.lineTo(150, 150); 576 path.lineTo(75, 150); 577 path.lineTo(75, 100); 578 canvas->drawPath(path, p); 579 // from zero_length_paths_aa 580 canvas->translate(0, 200); 581 path.reset(); 582 path.moveTo(150, 100); 583 path.lineTo(150, 100); 584 path.lineTo(150, 150); 585 path.lineTo(75, 150); 586 path.lineTo(75, 100); 587 path.lineTo(75, 75); 588 path.lineTo(150, 75); 589 path.close(); 590 canvas->drawPath(path, p); 591 // from skbug.com/7792#c41 592 canvas->translate(0, 200); 593 path.reset(); 594 path.moveTo(75, 75); 595 path.lineTo(150, 75); 596 path.lineTo(150, 150); 597 path.lineTo(140, 150); 598 path.lineTo(140, 75); 599 path.moveTo(75, 75); 600 path.close(); 601 canvas->drawPath(path, p); 602 // from skbug.com/7792#c53 603 canvas->translate(0, 200); 604 path.reset(); 605 path.moveTo(75, 75); 606 path.lineTo(150, 75); 607 path.lineTo(150, 150); 608 path.lineTo(140, 150); 609 path.lineTo(140, 75); 610 path.moveTo(75, 75); 611 path.close(); 612 canvas->drawPath(path, p); 613 } 614