1/* 2 * Copyright 2015 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 "SampleCode.h" 9#include "SkBitmap.h" 10#include "SkCanvas.h" 11#include "SkGeometry.h" 12#include "SkIntersections.h" 13#include "SkOpEdgeBuilder.h" 14// #include "SkPathOpsSimplifyAA.h" 15// #include "SkPathStroker.h" 16#include "SkPointPriv.h" 17#include "SkString.h" 18#include "SkView.h" 19 20#if 0 21void SkStrokeSegment::dump() const { 22 SkDebugf("{{{%1.9g,%1.9g}, {%1.9g,%1.9g}", fPts[0].fX, fPts[0].fY, fPts[1].fX, fPts[1].fY); 23 if (SkPath::kQuad_Verb == fVerb) { 24 SkDebugf(", {%1.9g,%1.9g}", fPts[2].fX, fPts[2].fY); 25 } 26 SkDebugf("}}"); 27#ifdef SK_DEBUG 28 SkDebugf(" id=%d", fDebugID); 29#endif 30 SkDebugf("\n"); 31} 32 33void SkStrokeSegment::dumpAll() const { 34 const SkStrokeSegment* segment = this; 35 while (segment) { 36 segment->dump(); 37 segment = segment->fNext; 38 } 39} 40 41void SkStrokeTriple::dump() const { 42 SkDebugf("{{{%1.9g,%1.9g}, {%1.9g,%1.9g}", fPts[0].fX, fPts[0].fY, fPts[1].fX, fPts[1].fY); 43 if (SkPath::kQuad_Verb <= fVerb) { 44 SkDebugf(", {%1.9g,%1.9g}", fPts[2].fX, fPts[2].fY); 45 } 46 if (SkPath::kCubic_Verb == fVerb) { 47 SkDebugf(", {%1.9g,%1.9g}", fPts[3].fX, fPts[3].fY); 48 } else if (SkPath::kConic_Verb == fVerb) { 49 SkDebugf(", %1.9g", weight()); 50 } 51 SkDebugf("}}"); 52#ifdef SK_DEBUG 53 SkDebugf(" triple id=%d", fDebugID); 54#endif 55 SkDebugf("\ninner:\n"); 56 fInner->dumpAll(); 57 SkDebugf("outer:\n"); 58 fOuter->dumpAll(); 59 SkDebugf("join:\n"); 60 fJoin->dumpAll(); 61} 62 63void SkStrokeTriple::dumpAll() const { 64 const SkStrokeTriple* triple = this; 65 while (triple) { 66 triple->dump(); 67 triple = triple->fNext; 68 } 69} 70 71void SkStrokeContour::dump() const { 72#ifdef SK_DEBUG 73 SkDebugf("id=%d ", fDebugID); 74#endif 75 SkDebugf("head:\n"); 76 fHead->dumpAll(); 77 SkDebugf("head cap:\n"); 78 fHeadCap->dumpAll(); 79 SkDebugf("tail cap:\n"); 80 fTailCap->dumpAll(); 81} 82 83void SkStrokeContour::dumpAll() const { 84 const SkStrokeContour* contour = this; 85 while (contour) { 86 contour->dump(); 87 contour = contour->fNext; 88 } 89} 90#endif 91 92SkScalar gCurveDistance = 10; 93 94#if 0 // unused 95static SkPath::Verb get_path_verb(int index, const SkPath& path) { 96 if (index < 0) { 97 return SkPath::kMove_Verb; 98 } 99 SkPoint pts[4]; 100 SkPath::Verb verb; 101 SkPath::Iter iter(path, true); 102 int counter = -1; 103 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { 104 if (++counter < index) { 105 continue; 106 } 107 return verb; 108 } 109 SkASSERT(0); 110 return SkPath::kMove_Verb; 111} 112#endif 113 114static SkScalar get_path_weight(int index, const SkPath& path) { 115 SkPoint pts[4]; 116 SkPath::Verb verb; 117 SkPath::Iter iter(path, true); 118 int counter = -1; 119 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { 120 if (++counter < index) { 121 continue; 122 } 123 return verb == SkPath::kConic_Verb ? iter.conicWeight() : 1; 124 } 125 SkASSERT(0); 126 return 0; 127} 128 129static void set_path_pt(int index, const SkPoint& pt, SkPath* path) { 130 SkPath result; 131 SkPoint pts[4]; 132 SkPath::Verb verb; 133 SkPath::RawIter iter(*path); 134 int startIndex = 0; 135 int endIndex = 0; 136 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { 137 switch (verb) { 138 case SkPath::kMove_Verb: 139 endIndex += 1; 140 break; 141 case SkPath::kLine_Verb: 142 endIndex += 1; 143 break; 144 case SkPath::kQuad_Verb: 145 case SkPath::kConic_Verb: 146 endIndex += 2; 147 break; 148 case SkPath::kCubic_Verb: 149 endIndex += 3; 150 break; 151 case SkPath::kClose_Verb: 152 break; 153 case SkPath::kDone_Verb: 154 break; 155 default: 156 SkASSERT(0); 157 } 158 if (startIndex <= index && index < endIndex) { 159 pts[index - startIndex] = pt; 160 index = -1; 161 } 162 switch (verb) { 163 case SkPath::kMove_Verb: 164 result.moveTo(pts[0]); 165 break; 166 case SkPath::kLine_Verb: 167 result.lineTo(pts[1]); 168 startIndex += 1; 169 break; 170 case SkPath::kQuad_Verb: 171 result.quadTo(pts[1], pts[2]); 172 startIndex += 2; 173 break; 174 case SkPath::kConic_Verb: 175 result.conicTo(pts[1], pts[2], iter.conicWeight()); 176 startIndex += 2; 177 break; 178 case SkPath::kCubic_Verb: 179 result.cubicTo(pts[1], pts[2], pts[3]); 180 startIndex += 3; 181 break; 182 case SkPath::kClose_Verb: 183 result.close(); 184 startIndex += 1; 185 break; 186 case SkPath::kDone_Verb: 187 break; 188 default: 189 SkASSERT(0); 190 } 191 } 192#if 0 193 SkDebugf("\n\noriginal\n"); 194 path->dump(); 195 SkDebugf("\nedited\n"); 196 result.dump(); 197#endif 198 *path = result; 199} 200 201static void add_path_segment(int index, SkPath* path) { 202 SkPath result; 203 SkPoint pts[4]; 204 SkPoint firstPt = { 0, 0 }; // init to avoid warning 205 SkPoint lastPt = { 0, 0 }; // init to avoid warning 206 SkPath::Verb verb; 207 SkPath::RawIter iter(*path); 208 int counter = -1; 209 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { 210 SkScalar weight SK_INIT_TO_AVOID_WARNING; 211 if (++counter == index) { 212 switch (verb) { 213 case SkPath::kLine_Verb: 214 result.lineTo((pts[0].fX + pts[1].fX) / 2, (pts[0].fY + pts[1].fY) / 2); 215 break; 216 case SkPath::kQuad_Verb: { 217 SkPoint chop[5]; 218 SkChopQuadAtHalf(pts, chop); 219 result.quadTo(chop[1], chop[2]); 220 pts[1] = chop[3]; 221 } break; 222 case SkPath::kConic_Verb: { 223 SkConic chop[2]; 224 SkConic conic; 225 conic.set(pts, iter.conicWeight()); 226 if (!conic.chopAt(0.5f, chop)) { 227 return; 228 } 229 result.conicTo(chop[0].fPts[1], chop[0].fPts[2], chop[0].fW); 230 pts[1] = chop[1].fPts[1]; 231 weight = chop[1].fW; 232 } break; 233 case SkPath::kCubic_Verb: { 234 SkPoint chop[7]; 235 SkChopCubicAtHalf(pts, chop); 236 result.cubicTo(chop[1], chop[2], chop[3]); 237 pts[1] = chop[4]; 238 pts[2] = chop[5]; 239 } break; 240 case SkPath::kClose_Verb: { 241 result.lineTo((lastPt.fX + firstPt.fX) / 2, (lastPt.fY + firstPt.fY) / 2); 242 } break; 243 default: 244 SkASSERT(0); 245 } 246 } else if (verb == SkPath::kConic_Verb) { 247 weight = iter.conicWeight(); 248 } 249 switch (verb) { 250 case SkPath::kMove_Verb: 251 result.moveTo(firstPt = pts[0]); 252 break; 253 case SkPath::kLine_Verb: 254 result.lineTo(lastPt = pts[1]); 255 break; 256 case SkPath::kQuad_Verb: 257 result.quadTo(pts[1], lastPt = pts[2]); 258 break; 259 case SkPath::kConic_Verb: 260 result.conicTo(pts[1], lastPt = pts[2], weight); 261 break; 262 case SkPath::kCubic_Verb: 263 result.cubicTo(pts[1], pts[2], lastPt = pts[3]); 264 break; 265 case SkPath::kClose_Verb: 266 result.close(); 267 break; 268 case SkPath::kDone_Verb: 269 break; 270 default: 271 SkASSERT(0); 272 } 273 } 274 *path = result; 275} 276 277static void delete_path_segment(int index, SkPath* path) { 278 SkPath result; 279 SkPoint pts[4]; 280 SkPath::Verb verb; 281 SkPath::RawIter iter(*path); 282 int counter = -1; 283 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { 284 if (++counter == index) { 285 continue; 286 } 287 switch (verb) { 288 case SkPath::kMove_Verb: 289 result.moveTo(pts[0]); 290 break; 291 case SkPath::kLine_Verb: 292 result.lineTo(pts[1]); 293 break; 294 case SkPath::kQuad_Verb: 295 result.quadTo(pts[1], pts[2]); 296 break; 297 case SkPath::kConic_Verb: 298 result.conicTo(pts[1], pts[2], iter.conicWeight()); 299 break; 300 case SkPath::kCubic_Verb: 301 result.cubicTo(pts[1], pts[2], pts[3]); 302 break; 303 case SkPath::kClose_Verb: 304 result.close(); 305 break; 306 case SkPath::kDone_Verb: 307 break; 308 default: 309 SkASSERT(0); 310 } 311 } 312 *path = result; 313} 314 315static void set_path_weight(int index, SkScalar w, SkPath* path) { 316 SkPath result; 317 SkPoint pts[4]; 318 SkPath::Verb verb; 319 SkPath::Iter iter(*path, true); 320 int counter = -1; 321 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { 322 ++counter; 323 switch (verb) { 324 case SkPath::kMove_Verb: 325 result.moveTo(pts[0]); 326 break; 327 case SkPath::kLine_Verb: 328 result.lineTo(pts[1]); 329 break; 330 case SkPath::kQuad_Verb: 331 result.quadTo(pts[1], pts[2]); 332 break; 333 case SkPath::kConic_Verb: 334 result.conicTo(pts[1], pts[2], counter == index ? w : iter.conicWeight()); 335 break; 336 case SkPath::kCubic_Verb: 337 result.cubicTo(pts[1], pts[2], pts[3]); 338 break; 339 case SkPath::kClose_Verb: 340 result.close(); 341 break; 342 case SkPath::kDone_Verb: 343 break; 344 default: 345 SkASSERT(0); 346 } 347 } 348 *path = result; 349} 350 351static void set_path_verb(int index, SkPath::Verb v, SkPath* path, SkScalar w) { 352 SkASSERT(SkPath::kLine_Verb <= v && v <= SkPath::kCubic_Verb); 353 SkPath result; 354 SkPoint pts[4]; 355 SkPath::Verb verb; 356 SkPath::Iter iter(*path, true); 357 int counter = -1; 358 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { 359 SkScalar weight = verb == SkPath::kConic_Verb ? iter.conicWeight() : 1; 360 if (++counter == index && v != verb) { 361 SkASSERT(SkPath::kLine_Verb <= verb && verb <= SkPath::kCubic_Verb); 362 switch (verb) { 363 case SkPath::kLine_Verb: 364 switch (v) { 365 case SkPath::kConic_Verb: 366 weight = w; 367 case SkPath::kQuad_Verb: 368 pts[2] = pts[1]; 369 pts[1].fX = (pts[0].fX + pts[2].fX) / 2; 370 pts[1].fY = (pts[0].fY + pts[2].fY) / 2; 371 break; 372 case SkPath::kCubic_Verb: 373 pts[3] = pts[1]; 374 pts[1].fX = (pts[0].fX * 2 + pts[3].fX) / 3; 375 pts[1].fY = (pts[0].fY * 2 + pts[3].fY) / 3; 376 pts[2].fX = (pts[0].fX + pts[3].fX * 2) / 3; 377 pts[2].fY = (pts[0].fY + pts[3].fY * 2) / 3; 378 break; 379 default: 380 SkASSERT(0); 381 break; 382 } 383 break; 384 case SkPath::kQuad_Verb: 385 case SkPath::kConic_Verb: 386 switch (v) { 387 case SkPath::kLine_Verb: 388 pts[1] = pts[2]; 389 break; 390 case SkPath::kConic_Verb: 391 weight = w; 392 case SkPath::kQuad_Verb: 393 break; 394 case SkPath::kCubic_Verb: { 395 SkDQuad dQuad; 396 dQuad.set(pts); 397 SkDCubic dCubic = dQuad.debugToCubic(); 398 pts[3] = pts[2]; 399 pts[1] = dCubic[1].asSkPoint(); 400 pts[2] = dCubic[2].asSkPoint(); 401 } break; 402 default: 403 SkASSERT(0); 404 break; 405 } 406 break; 407 case SkPath::kCubic_Verb: 408 switch (v) { 409 case SkPath::kLine_Verb: 410 pts[1] = pts[3]; 411 break; 412 case SkPath::kConic_Verb: 413 weight = w; 414 case SkPath::kQuad_Verb: { 415 SkDCubic dCubic; 416 dCubic.set(pts); 417 SkDQuad dQuad = dCubic.toQuad(); 418 pts[1] = dQuad[1].asSkPoint(); 419 pts[2] = pts[3]; 420 } break; 421 default: 422 SkASSERT(0); 423 break; 424 } 425 break; 426 default: 427 SkASSERT(0); 428 break; 429 } 430 verb = v; 431 } 432 switch (verb) { 433 case SkPath::kMove_Verb: 434 result.moveTo(pts[0]); 435 break; 436 case SkPath::kLine_Verb: 437 result.lineTo(pts[1]); 438 break; 439 case SkPath::kQuad_Verb: 440 result.quadTo(pts[1], pts[2]); 441 break; 442 case SkPath::kConic_Verb: 443 result.conicTo(pts[1], pts[2], weight); 444 break; 445 case SkPath::kCubic_Verb: 446 result.cubicTo(pts[1], pts[2], pts[3]); 447 break; 448 case SkPath::kClose_Verb: 449 result.close(); 450 break; 451 default: 452 SkASSERT(0); 453 break; 454 } 455 } 456 *path = result; 457} 458 459static void add_to_map(SkScalar coverage, int x, int y, uint8_t* distanceMap, int w, int h) { 460 int byteCoverage = (int) (coverage * 256); 461 if (byteCoverage < 0) { 462 byteCoverage = 0; 463 } else if (byteCoverage > 255) { 464 byteCoverage = 255; 465 } 466 SkASSERT(x < w); 467 SkASSERT(y < h); 468 distanceMap[y * w + x] = SkTMax(distanceMap[y * w + x], (uint8_t) byteCoverage); 469} 470 471static void filter_coverage(const uint8_t* map, int len, uint8_t min, uint8_t max, 472 uint8_t* filter) { 473 for (int index = 0; index < len; ++index) { 474 uint8_t in = map[index]; 475 filter[index] = in < min ? 0 : max < in ? 0 : in; 476 } 477} 478 479static void construct_path(SkPath& path) { 480 path.reset(); 481 path.moveTo(442, 101.5f); 482 path.quadTo(413.5f, 691, 772, 514); 483 path.lineTo(346, 721.5f); 484 path.lineTo(154, 209); 485 path.lineTo(442, 101.5f); 486 path.close(); 487} 488 489struct ButtonPaints { 490 static const int kMaxStateCount = 3; 491 SkPaint fDisabled; 492 SkPaint fStates[kMaxStateCount]; 493 SkPaint fLabel; 494 495 ButtonPaints() { 496 fStates[0].setAntiAlias(true); 497 fStates[0].setStyle(SkPaint::kStroke_Style); 498 fStates[0].setColor(0xFF3F0000); 499 fStates[1] = fStates[0]; 500 fStates[1].setStrokeWidth(3); 501 fStates[2] = fStates[1]; 502 fStates[2].setColor(0xFFcf0000); 503 fLabel.setAntiAlias(true); 504 fLabel.setTextSize(25.0f); 505 fLabel.setTextAlign(SkPaint::kCenter_Align); 506 fLabel.setStyle(SkPaint::kFill_Style); 507 } 508}; 509 510struct Button { 511 SkRect fBounds; 512 int fStateCount; 513 int fState; 514 char fLabel; 515 bool fVisible; 516 517 Button(char label) { 518 fStateCount = 2; 519 fState = 0; 520 fLabel = label; 521 fVisible = false; 522 } 523 524 Button(char label, int stateCount) { 525 SkASSERT(stateCount <= ButtonPaints::kMaxStateCount); 526 fStateCount = stateCount; 527 fState = 0; 528 fLabel = label; 529 fVisible = false; 530 } 531 532 bool contains(const SkRect& rect) { 533 return fVisible && fBounds.contains(rect); 534 } 535 536 bool enabled() { 537 return SkToBool(fState); 538 } 539 540 void draw(SkCanvas* canvas, const ButtonPaints& paints) { 541 if (!fVisible) { 542 return; 543 } 544 canvas->drawRect(fBounds, paints.fStates[fState]); 545 canvas->drawText(&fLabel, 1, fBounds.centerX(), fBounds.fBottom - 5, paints.fLabel); 546 } 547 548 void toggle() { 549 if (++fState == fStateCount) { 550 fState = 0; 551 } 552 } 553 554 void setEnabled(bool enabled) { 555 fState = (int) enabled; 556 } 557}; 558 559struct ControlPaints { 560 SkPaint fOutline; 561 SkPaint fIndicator; 562 SkPaint fFill; 563 SkPaint fLabel; 564 SkPaint fValue; 565 566 ControlPaints() { 567 fOutline.setAntiAlias(true); 568 fOutline.setStyle(SkPaint::kStroke_Style); 569 fIndicator = fOutline; 570 fIndicator.setColor(SK_ColorRED); 571 fFill.setAntiAlias(true); 572 fFill.setColor(0x7fff0000); 573 fLabel.setAntiAlias(true); 574 fLabel.setTextSize(13.0f); 575 fValue.setAntiAlias(true); 576 fValue.setTextSize(11.0f); 577 } 578}; 579 580struct UniControl { 581 SkString fName; 582 SkRect fBounds; 583 SkScalar fMin; 584 SkScalar fMax; 585 SkScalar fValLo; 586 SkScalar fYLo; 587 bool fVisible; 588 589 UniControl(const char* name, SkScalar min, SkScalar max) { 590 fName = name; 591 fValLo = fMin = min; 592 fMax = max; 593 fVisible = false; 594 595 } 596 597 virtual ~UniControl() {} 598 599 bool contains(const SkRect& rect) { 600 return fVisible && fBounds.contains(rect); 601 } 602 603 virtual void draw(SkCanvas* canvas, const ControlPaints& paints) { 604 if (!fVisible) { 605 return; 606 } 607 canvas->drawRect(fBounds, paints.fOutline); 608 fYLo = fBounds.fTop + (fValLo - fMin) * fBounds.height() / (fMax - fMin); 609 canvas->drawLine(fBounds.fLeft - 5, fYLo, fBounds.fRight + 5, fYLo, paints.fIndicator); 610 SkString label; 611 label.printf("%0.3g", fValLo); 612 canvas->drawString(label, fBounds.fLeft + 5, fYLo - 5, paints.fValue); 613 canvas->drawString(fName, fBounds.fLeft, fBounds.bottom() + 11, 614 paints.fLabel); 615 } 616}; 617 618struct BiControl : public UniControl { 619 SkScalar fValHi; 620 621 BiControl(const char* name, SkScalar min, SkScalar max) 622 : UniControl(name, min, max) 623 , fValHi(fMax) { 624 } 625 626 virtual ~BiControl() {} 627 628 virtual void draw(SkCanvas* canvas, const ControlPaints& paints) { 629 UniControl::draw(canvas, paints); 630 if (!fVisible || fValHi == fValLo) { 631 return; 632 } 633 SkScalar yPos = fBounds.fTop + (fValHi - fMin) * fBounds.height() / (fMax - fMin); 634 canvas->drawLine(fBounds.fLeft - 5, yPos, fBounds.fRight + 5, yPos, paints.fIndicator); 635 SkString label; 636 label.printf("%0.3g", fValHi); 637 if (yPos < fYLo + 10) { 638 yPos = fYLo + 10; 639 } 640 canvas->drawString(label, fBounds.fLeft + 5, yPos - 5, paints.fValue); 641 SkRect fill = { fBounds.fLeft, fYLo, fBounds.fRight, yPos }; 642 canvas->drawRect(fill, paints.fFill); 643 } 644}; 645 646 647class MyClick : public SampleView::Click { 648public: 649 enum ClickType { 650 kInvalidType = -1, 651 kPtType, 652 kVerbType, 653 kControlType, 654 kPathType, 655 } fType; 656 657 enum ControlType { 658 kInvalidControl = -1, 659 kFirstControl, 660 kFilterControl = kFirstControl, 661 kResControl, 662 kWeightControl, 663 kWidthControl, 664 kLastControl = kWidthControl, 665 kFirstButton, 666 kCubicButton = kFirstButton, 667 kConicButton, 668 kQuadButton, 669 kLineButton, 670 kLastVerbButton = kLineButton, 671 kAddButton, 672 kDeleteButton, 673 kInOutButton, 674 kFillButton, 675 kSkeletonButton, 676 kFilterButton, 677 kBisectButton, 678 kJoinButton, 679 kLastButton = kJoinButton, 680 kPathMove, 681 } fControl; 682 683 SkPath::Verb fVerb; 684 SkScalar fWeight; 685 686 MyClick(SkView* target, ClickType type, ControlType control) 687 : Click(target) 688 , fType(type) 689 , fControl(control) 690 , fVerb((SkPath::Verb) -1) 691 , fWeight(1) { 692 } 693 694 MyClick(SkView* target, ClickType type, int index) 695 : Click(target) 696 , fType(type) 697 , fControl((ControlType) index) 698 , fVerb((SkPath::Verb) -1) 699 , fWeight(1) { 700 } 701 702 MyClick(SkView* target, ClickType type, int index, SkPath::Verb verb, SkScalar weight) 703 : Click(target) 704 , fType(type) 705 , fControl((ControlType) index) 706 , fVerb(verb) 707 , fWeight(weight) { 708 } 709 710 bool isButton() { 711 return kFirstButton <= fControl && fControl <= kLastButton; 712 } 713 714 int ptHit() const { 715 SkASSERT(fType == kPtType); 716 return (int) fControl; 717 } 718 719 int verbHit() const { 720 SkASSERT(fType == kVerbType); 721 return (int) fControl; 722 } 723}; 724 725enum { 726 kControlCount = MyClick::kLastControl - MyClick::kFirstControl + 1, 727}; 728 729static struct ControlPair { 730 UniControl* fControl; 731 MyClick::ControlType fControlType; 732} kControlList[kControlCount]; 733 734enum { 735 kButtonCount = MyClick::kLastButton - MyClick::kFirstButton + 1, 736 kVerbCount = MyClick::kLastVerbButton - MyClick::kFirstButton + 1, 737}; 738 739static struct ButtonPair { 740 Button* fButton; 741 MyClick::ControlType fButtonType; 742} kButtonList[kButtonCount]; 743 744static void enable_verb_button(MyClick::ControlType type) { 745 for (int index = 0; index < kButtonCount; ++index) { 746 MyClick::ControlType testType = kButtonList[index].fButtonType; 747 if (MyClick::kFirstButton <= testType && testType <= MyClick::kLastVerbButton) { 748 Button* button = kButtonList[index].fButton; 749 button->setEnabled(testType == type); 750 } 751 } 752} 753 754struct Stroke; 755 756struct Active { 757 Active* fNext; 758 Stroke* fParent; 759 SkScalar fStart; 760 SkScalar fEnd; 761 762 void reset() { 763 fNext = nullptr; 764 fStart = 0; 765 fEnd = 1; 766 } 767}; 768 769struct Stroke { 770 SkPath fPath; 771 Active fActive; 772 bool fInner; 773 774 void reset() { 775 fPath.reset(); 776 fActive.reset(); 777 } 778}; 779 780struct PathUndo { 781 SkPath fPath; 782 PathUndo* fNext; 783}; 784 785class AAGeometryView : public SampleView { 786 SkPaint fActivePaint; 787 SkPaint fComplexPaint; 788 SkPaint fCoveragePaint; 789 SkPaint fLegendLeftPaint; 790 SkPaint fLegendRightPaint; 791 SkPaint fPointPaint; 792 SkPaint fSkeletonPaint; 793 SkPaint fLightSkeletonPaint; 794 SkPath fPath; 795 ControlPaints fControlPaints; 796 UniControl fResControl; 797 UniControl fWeightControl; 798 UniControl fWidthControl; 799 BiControl fFilterControl; 800 ButtonPaints fButtonPaints; 801 Button fCubicButton; 802 Button fConicButton; 803 Button fQuadButton; 804 Button fLineButton; 805 Button fAddButton; 806 Button fDeleteButton; 807 Button fFillButton; 808 Button fSkeletonButton; 809 Button fFilterButton; 810 Button fBisectButton; 811 Button fJoinButton; 812 Button fInOutButton; 813 SkTArray<Stroke> fStrokes; 814 PathUndo* fUndo; 815 int fActivePt; 816 int fActiveVerb; 817 bool fHandlePathMove; 818 bool fShowLegend; 819 bool fHideAll; 820 const int kHitToleranace = 25; 821 822public: 823 824 AAGeometryView() 825 : fResControl("error", 0, 10) 826 , fWeightControl("weight", 0, 5) 827 , fWidthControl("width", FLT_EPSILON, 100) 828 , fFilterControl("filter", 0, 255) 829 , fCubicButton('C') 830 , fConicButton('K') 831 , fQuadButton('Q') 832 , fLineButton('L') 833 , fAddButton('+') 834 , fDeleteButton('x') 835 , fFillButton('p') 836 , fSkeletonButton('s') 837 , fFilterButton('f', 3) 838 , fBisectButton('b') 839 , fJoinButton('j') 840 , fInOutButton('|') 841 , fUndo(nullptr) 842 , fActivePt(-1) 843 , fActiveVerb(-1) 844 , fHandlePathMove(true) 845 , fShowLegend(false) 846 , fHideAll(false) 847 { 848 fCoveragePaint.setAntiAlias(true); 849 fCoveragePaint.setColor(SK_ColorBLUE); 850 SkPaint strokePaint; 851 strokePaint.setAntiAlias(true); 852 strokePaint.setStyle(SkPaint::kStroke_Style); 853 fPointPaint = strokePaint; 854 fPointPaint.setColor(0x99ee3300); 855 fSkeletonPaint = strokePaint; 856 fSkeletonPaint.setColor(SK_ColorRED); 857 fLightSkeletonPaint = fSkeletonPaint; 858 fLightSkeletonPaint.setColor(0xFFFF7f7f); 859 fActivePaint = strokePaint; 860 fActivePaint.setColor(0x99ee3300); 861 fActivePaint.setStrokeWidth(5); 862 fComplexPaint = fActivePaint; 863 fComplexPaint.setColor(SK_ColorBLUE); 864 fLegendLeftPaint.setAntiAlias(true); 865 fLegendLeftPaint.setTextSize(13); 866 fLegendRightPaint = fLegendLeftPaint; 867 fLegendRightPaint.setTextAlign(SkPaint::kRight_Align); 868 construct_path(fPath); 869 fFillButton.fVisible = fSkeletonButton.fVisible = fFilterButton.fVisible 870 = fBisectButton.fVisible = fJoinButton.fVisible = fInOutButton.fVisible = true; 871 fSkeletonButton.setEnabled(true); 872 fInOutButton.setEnabled(true); 873 fJoinButton.setEnabled(true); 874 fFilterControl.fValLo = 120; 875 fFilterControl.fValHi = 141; 876 fFilterControl.fVisible = fFilterButton.fState == 2; 877 fResControl.fValLo = 5; 878 fResControl.fVisible = true; 879 fWidthControl.fValLo = 50; 880 fWidthControl.fVisible = true; 881 init_controlList(); 882 init_buttonList(); 883 } 884 885 bool constructPath() { 886 construct_path(fPath); 887 return true; 888 } 889 890 void savePath(Click::State state) { 891 if (state != Click::kDown_State) { 892 return; 893 } 894 if (fUndo && fUndo->fPath == fPath) { 895 return; 896 } 897 PathUndo* undo = new PathUndo; 898 undo->fPath = fPath; 899 undo->fNext = fUndo; 900 fUndo = undo; 901 } 902 903 bool undo() { 904 if (!fUndo) { 905 return false; 906 } 907 fPath = fUndo->fPath; 908 validatePath(); 909 PathUndo* next = fUndo->fNext; 910 delete fUndo; 911 fUndo = next; 912 return true; 913 } 914 915 void validatePath() { 916 PathUndo* undo = fUndo; 917 int match = 0; 918 while (undo) { 919 match += fPath == undo->fPath; 920 undo = undo->fNext; 921 } 922 } 923 924 void set_controlList(int index, UniControl* control, MyClick::ControlType type) { 925 kControlList[index].fControl = control; 926 kControlList[index].fControlType = type; 927 } 928 929 #define SET_CONTROL(Name) set_controlList(index++, &f##Name##Control, \ 930 MyClick::k##Name##Control) 931 932 bool hideAll() { 933 fHideAll ^= true; 934 return true; 935 } 936 937 void init_controlList() { 938 int index = 0; 939 SET_CONTROL(Width); 940 SET_CONTROL(Res); 941 SET_CONTROL(Filter); 942 SET_CONTROL(Weight); 943 } 944 945 #undef SET_CONTROL 946 947 void set_buttonList(int index, Button* button, MyClick::ControlType type) { 948 kButtonList[index].fButton = button; 949 kButtonList[index].fButtonType = type; 950 } 951 952 #define SET_BUTTON(Name) set_buttonList(index++, &f##Name##Button, \ 953 MyClick::k##Name##Button) 954 955 void init_buttonList() { 956 int index = 0; 957 SET_BUTTON(Fill); 958 SET_BUTTON(Skeleton); 959 SET_BUTTON(Filter); 960 SET_BUTTON(Bisect); 961 SET_BUTTON(Join); 962 SET_BUTTON(InOut); 963 SET_BUTTON(Cubic); 964 SET_BUTTON(Conic); 965 SET_BUTTON(Quad); 966 SET_BUTTON(Line); 967 SET_BUTTON(Add); 968 SET_BUTTON(Delete); 969 } 970 971 #undef SET_BUTTON 972 973 // overrides from SkEventSink 974 bool onQuery(SkEvent* evt) override; 975 976 void onSizeChange() override { 977 setControlButtonsPos(); 978 this->INHERITED::onSizeChange(); 979 } 980 981 bool pathDump() { 982 fPath.dump(); 983 return true; 984 } 985 986 bool scaleDown() { 987 SkMatrix matrix; 988 SkRect bounds = fPath.getBounds(); 989 matrix.setScale(1.f / 1.5f, 1.f / 1.5f, bounds.centerX(), bounds.centerY()); 990 fPath.transform(matrix); 991 validatePath(); 992 return true; 993 } 994 995 bool scaleToFit() { 996 SkMatrix matrix; 997 SkRect bounds = fPath.getBounds(); 998 SkScalar scale = SkTMin(this->width() / bounds.width(), this->height() / bounds.height()) 999 * 0.8f; 1000 matrix.setScale(scale, scale, bounds.centerX(), bounds.centerY()); 1001 fPath.transform(matrix); 1002 bounds = fPath.getBounds(); 1003 SkScalar offsetX = (this->width() - bounds.width()) / 2 - bounds.fLeft; 1004 SkScalar offsetY = (this->height() - bounds.height()) / 2 - bounds.fTop; 1005 fPath.offset(offsetX, offsetY); 1006 validatePath(); 1007 return true; 1008 } 1009 1010 bool scaleUp() { 1011 SkMatrix matrix; 1012 SkRect bounds = fPath.getBounds(); 1013 matrix.setScale(1.5f, 1.5f, bounds.centerX(), bounds.centerY()); 1014 fPath.transform(matrix); 1015 validatePath(); 1016 return true; 1017 } 1018 1019 void setControlButtonsPos() { 1020 SkScalar widthOffset = this->width() - 100; 1021 for (int index = 0; index < kControlCount; ++index) { 1022 if (kControlList[index].fControl->fVisible) { 1023 kControlList[index].fControl->fBounds.setXYWH(widthOffset, 30, 30, 400); 1024 widthOffset -= 50; 1025 } 1026 } 1027 SkScalar buttonOffset = 0; 1028 for (int index = 0; index < kButtonCount; ++index) { 1029 kButtonList[index].fButton->fBounds.setXYWH(this->width() - 50, 1030 buttonOffset += 50, 30, 30); 1031 } 1032 } 1033 1034 bool showLegend() { 1035 fShowLegend ^= true; 1036 return true; 1037 } 1038 1039 void draw_bisect(SkCanvas* canvas, const SkVector& lastVector, const SkVector& vector, 1040 const SkPoint& pt) { 1041 SkVector lastV = lastVector; 1042 SkScalar lastLen = lastVector.length(); 1043 SkVector nextV = vector; 1044 SkScalar nextLen = vector.length(); 1045 if (lastLen < nextLen) { 1046 lastV.setLength(nextLen); 1047 } else { 1048 nextV.setLength(lastLen); 1049 } 1050 1051 SkVector bisect = { (lastV.fX + nextV.fX) / 2, (lastV.fY + nextV.fY) / 2 }; 1052 bisect.setLength(fWidthControl.fValLo * 2); 1053 if (fBisectButton.enabled()) { 1054 canvas->drawLine(pt, pt + bisect, fSkeletonPaint); 1055 } 1056 lastV.setLength(fWidthControl.fValLo); 1057 if (fBisectButton.enabled()) { 1058 canvas->drawLine(pt, {pt.fX - lastV.fY, pt.fY + lastV.fX}, fSkeletonPaint); 1059 } 1060 nextV.setLength(fWidthControl.fValLo); 1061 if (fBisectButton.enabled()) { 1062 canvas->drawLine(pt, {pt.fX + nextV.fY, pt.fY - nextV.fX}, fSkeletonPaint); 1063 } 1064 if (fJoinButton.enabled()) { 1065 SkScalar r = fWidthControl.fValLo; 1066 SkRect oval = { pt.fX - r, pt.fY - r, pt.fX + r, pt.fY + r}; 1067 SkScalar startAngle = SkScalarATan2(lastV.fX, -lastV.fY) * 180.f / SK_ScalarPI; 1068 SkScalar endAngle = SkScalarATan2(-nextV.fX, nextV.fY) * 180.f / SK_ScalarPI; 1069 if (endAngle > startAngle) { 1070 canvas->drawArc(oval, startAngle, endAngle - startAngle, false, fSkeletonPaint); 1071 } else { 1072 canvas->drawArc(oval, startAngle, 360 - (startAngle - endAngle), false, 1073 fSkeletonPaint); 1074 } 1075 } 1076 } 1077 1078 void draw_bisects(SkCanvas* canvas, bool activeOnly) { 1079 SkVector firstVector, lastVector, nextLast, vector; 1080 SkPoint pts[4]; 1081 SkPoint firstPt = { 0, 0 }; // init to avoid warning; 1082 SkPath::Verb verb; 1083 SkPath::Iter iter(fPath, true); 1084 bool foundFirst = false; 1085 int counter = -1; 1086 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { 1087 ++counter; 1088 if (activeOnly && counter != fActiveVerb && counter - 1 != fActiveVerb 1089 && counter + 1 != fActiveVerb 1090 && (fActiveVerb != 1 || counter != fPath.countVerbs())) { 1091 continue; 1092 } 1093 switch (verb) { 1094 case SkPath::kLine_Verb: 1095 nextLast = pts[0] - pts[1]; 1096 vector = pts[1] - pts[0]; 1097 break; 1098 case SkPath::kQuad_Verb: { 1099 nextLast = pts[1] - pts[2]; 1100 if (SkScalarNearlyZero(nextLast.length())) { 1101 nextLast = pts[0] - pts[2]; 1102 } 1103 vector = pts[1] - pts[0]; 1104 if (SkScalarNearlyZero(vector.length())) { 1105 vector = pts[2] - pts[0]; 1106 } 1107 if (!fBisectButton.enabled()) { 1108 break; 1109 } 1110 SkScalar t = SkFindQuadMaxCurvature(pts); 1111 if (0 < t && t < 1) { 1112 SkPoint maxPt = SkEvalQuadAt(pts, t); 1113 SkVector tangent = SkEvalQuadTangentAt(pts, t); 1114 tangent.setLength(fWidthControl.fValLo * 2); 1115 canvas->drawLine(maxPt, {maxPt.fX + tangent.fY, maxPt.fY - tangent.fX}, 1116 fSkeletonPaint); 1117 } 1118 } break; 1119 case SkPath::kConic_Verb: 1120 nextLast = pts[1] - pts[2]; 1121 if (SkScalarNearlyZero(nextLast.length())) { 1122 nextLast = pts[0] - pts[2]; 1123 } 1124 vector = pts[1] - pts[0]; 1125 if (SkScalarNearlyZero(vector.length())) { 1126 vector = pts[2] - pts[0]; 1127 } 1128 if (!fBisectButton.enabled()) { 1129 break; 1130 } 1131 // FIXME : need max curvature or equivalent here 1132 break; 1133 case SkPath::kCubic_Verb: { 1134 nextLast = pts[2] - pts[3]; 1135 if (SkScalarNearlyZero(nextLast.length())) { 1136 nextLast = pts[1] - pts[3]; 1137 if (SkScalarNearlyZero(nextLast.length())) { 1138 nextLast = pts[0] - pts[3]; 1139 } 1140 } 1141 vector = pts[0] - pts[1]; 1142 if (SkScalarNearlyZero(vector.length())) { 1143 vector = pts[0] - pts[2]; 1144 if (SkScalarNearlyZero(vector.length())) { 1145 vector = pts[0] - pts[3]; 1146 } 1147 } 1148 if (!fBisectButton.enabled()) { 1149 break; 1150 } 1151 SkScalar tMax[2]; 1152 int tMaxCount = SkFindCubicMaxCurvature(pts, tMax); 1153 for (int tIndex = 0; tIndex < tMaxCount; ++tIndex) { 1154 if (0 >= tMax[tIndex] || tMax[tIndex] >= 1) { 1155 continue; 1156 } 1157 SkPoint maxPt; 1158 SkVector tangent; 1159 SkEvalCubicAt(pts, tMax[tIndex], &maxPt, &tangent, nullptr); 1160 tangent.setLength(fWidthControl.fValLo * 2); 1161 canvas->drawLine(maxPt, {maxPt.fX + tangent.fY, maxPt.fY - tangent.fX}, 1162 fSkeletonPaint); 1163 } 1164 } break; 1165 case SkPath::kClose_Verb: 1166 if (foundFirst) { 1167 draw_bisect(canvas, lastVector, firstVector, firstPt); 1168 foundFirst = false; 1169 } 1170 break; 1171 default: 1172 break; 1173 } 1174 if (SkPath::kLine_Verb <= verb && verb <= SkPath::kCubic_Verb) { 1175 if (!foundFirst) { 1176 firstPt = pts[0]; 1177 firstVector = vector; 1178 foundFirst = true; 1179 } else { 1180 draw_bisect(canvas, lastVector, vector, pts[0]); 1181 } 1182 lastVector = nextLast; 1183 } 1184 } 1185 } 1186 1187 void draw_legend(SkCanvas* canvas); 1188 1189 void draw_segment(SkCanvas* canvas) { 1190 SkPoint pts[4]; 1191 SkPath::Verb verb; 1192 SkPath::Iter iter(fPath, true); 1193 int counter = -1; 1194 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { 1195 if (++counter < fActiveVerb) { 1196 continue; 1197 } 1198 switch (verb) { 1199 case SkPath::kLine_Verb: 1200 canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts, fActivePaint); 1201 draw_points(canvas, pts, 2); 1202 break; 1203 case SkPath::kQuad_Verb: { 1204 SkPath qPath; 1205 qPath.moveTo(pts[0]); 1206 qPath.quadTo(pts[1], pts[2]); 1207 canvas->drawPath(qPath, fActivePaint); 1208 draw_points(canvas, pts, 3); 1209 } break; 1210 case SkPath::kConic_Verb: { 1211 SkPath conicPath; 1212 conicPath.moveTo(pts[0]); 1213 conicPath.conicTo(pts[1], pts[2], iter.conicWeight()); 1214 canvas->drawPath(conicPath, fActivePaint); 1215 draw_points(canvas, pts, 3); 1216 } break; 1217 case SkPath::kCubic_Verb: { 1218 SkScalar loopT[3]; 1219 int complex = SkDCubic::ComplexBreak(pts, loopT); 1220 SkPath cPath; 1221 cPath.moveTo(pts[0]); 1222 cPath.cubicTo(pts[1], pts[2], pts[3]); 1223 canvas->drawPath(cPath, complex ? fComplexPaint : fActivePaint); 1224 draw_points(canvas, pts, 4); 1225 } break; 1226 default: 1227 break; 1228 } 1229 return; 1230 } 1231 } 1232 1233 void draw_points(SkCanvas* canvas, SkPoint* points, int count) { 1234 for (int index = 0; index < count; ++index) { 1235 canvas->drawCircle(points[index].fX, points[index].fY, 10, fPointPaint); 1236 } 1237 } 1238 1239 int hittest_verb(SkPoint pt, SkPath::Verb* verbPtr, SkScalar* weight) { 1240 SkIntersections i; 1241 SkDLine hHit = {{{pt.fX - kHitToleranace, pt.fY }, {pt.fX + kHitToleranace, pt.fY}}}; 1242 SkDLine vHit = {{{pt.fX, pt.fY - kHitToleranace }, {pt.fX, pt.fY + kHitToleranace}}}; 1243 SkPoint pts[4]; 1244 SkPath::Verb verb; 1245 SkPath::Iter iter(fPath, true); 1246 int counter = -1; 1247 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { 1248 ++counter; 1249 switch (verb) { 1250 case SkPath::kLine_Verb: { 1251 SkDLine line; 1252 line.set(pts); 1253 if (i.intersect(line, hHit) || i.intersect(line, vHit)) { 1254 *verbPtr = verb; 1255 *weight = 1; 1256 return counter; 1257 } 1258 } break; 1259 case SkPath::kQuad_Verb: { 1260 SkDQuad quad; 1261 quad.set(pts); 1262 if (i.intersect(quad, hHit) || i.intersect(quad, vHit)) { 1263 *verbPtr = verb; 1264 *weight = 1; 1265 return counter; 1266 } 1267 } break; 1268 case SkPath::kConic_Verb: { 1269 SkDConic conic; 1270 SkScalar w = iter.conicWeight(); 1271 conic.set(pts, w); 1272 if (i.intersect(conic, hHit) || i.intersect(conic, vHit)) { 1273 *verbPtr = verb; 1274 *weight = w; 1275 return counter; 1276 } 1277 } break; 1278 case SkPath::kCubic_Verb: { 1279 SkDCubic cubic; 1280 cubic.set(pts); 1281 if (i.intersect(cubic, hHit) || i.intersect(cubic, vHit)) { 1282 *verbPtr = verb; 1283 *weight = 1; 1284 return counter; 1285 } 1286 } break; 1287 default: 1288 break; 1289 } 1290 } 1291 return -1; 1292 } 1293 1294 SkScalar pt_to_line(SkPoint s, SkPoint e, int x, int y) { 1295 SkScalar radius = fWidthControl.fValLo; 1296 SkVector adjOpp = e - s; 1297 SkScalar lenSq = SkPointPriv::LengthSqd(adjOpp); 1298 SkPoint rotated = { 1299 (y - s.fY) * adjOpp.fY + (x - s.fX) * adjOpp.fX, 1300 (y - s.fY) * adjOpp.fX - (x - s.fX) * adjOpp.fY, 1301 }; 1302 if (rotated.fX < 0 || rotated.fX > lenSq) { 1303 return -radius; 1304 } 1305 rotated.fY /= SkScalarSqrt(lenSq); 1306 return SkTMax(-radius, SkTMin(radius, rotated.fY)); 1307 } 1308 1309 // given a line, compute the interior and exterior gradient coverage 1310 bool coverage(SkPoint s, SkPoint e, uint8_t* distanceMap, int w, int h) { 1311 SkScalar radius = fWidthControl.fValLo; 1312 int minX = SkTMax(0, (int) (SkTMin(s.fX, e.fX) - radius)); 1313 int minY = SkTMax(0, (int) (SkTMin(s.fY, e.fY) - radius)); 1314 int maxX = SkTMin(w, (int) (SkTMax(s.fX, e.fX) + radius) + 1); 1315 int maxY = SkTMin(h, (int) (SkTMax(s.fY, e.fY) + radius) + 1); 1316 for (int y = minY; y < maxY; ++y) { 1317 for (int x = minX; x < maxX; ++x) { 1318 SkScalar ptToLineDist = pt_to_line(s, e, x, y); 1319 if (ptToLineDist > -radius && ptToLineDist < radius) { 1320 SkScalar coverage = ptToLineDist / radius; 1321 add_to_map(1 - SkScalarAbs(coverage), x, y, distanceMap, w, h); 1322 } 1323 SkVector ptToS = { x - s.fX, y - s.fY }; 1324 SkScalar dist = ptToS.length(); 1325 if (dist < radius) { 1326 SkScalar coverage = dist / radius; 1327 add_to_map(1 - SkScalarAbs(coverage), x, y, distanceMap, w, h); 1328 } 1329 SkVector ptToE = { x - e.fX, y - e.fY }; 1330 dist = ptToE.length(); 1331 if (dist < radius) { 1332 SkScalar coverage = dist / radius; 1333 add_to_map(1 - SkScalarAbs(coverage), x, y, distanceMap, w, h); 1334 } 1335 } 1336 } 1337 return true; 1338 } 1339 1340 void quad_coverage(SkPoint pts[3], uint8_t* distanceMap, int w, int h) { 1341 SkScalar dist = pts[0].Distance(pts[0], pts[2]); 1342 if (dist < gCurveDistance) { 1343 (void) coverage(pts[0], pts[2], distanceMap, w, h); 1344 return; 1345 } 1346 SkPoint split[5]; 1347 SkChopQuadAt(pts, split, 0.5f); 1348 quad_coverage(&split[0], distanceMap, w, h); 1349 quad_coverage(&split[2], distanceMap, w, h); 1350 } 1351 1352 void conic_coverage(SkPoint pts[3], SkScalar weight, uint8_t* distanceMap, int w, int h) { 1353 SkScalar dist = pts[0].Distance(pts[0], pts[2]); 1354 if (dist < gCurveDistance) { 1355 (void) coverage(pts[0], pts[2], distanceMap, w, h); 1356 return; 1357 } 1358 SkConic split[2]; 1359 SkConic conic; 1360 conic.set(pts, weight); 1361 if (conic.chopAt(0.5f, split)) { 1362 conic_coverage(split[0].fPts, split[0].fW, distanceMap, w, h); 1363 conic_coverage(split[1].fPts, split[1].fW, distanceMap, w, h); 1364 } 1365 } 1366 1367 void cubic_coverage(SkPoint pts[4], uint8_t* distanceMap, int w, int h) { 1368 SkScalar dist = pts[0].Distance(pts[0], pts[3]); 1369 if (dist < gCurveDistance) { 1370 (void) coverage(pts[0], pts[3], distanceMap, w, h); 1371 return; 1372 } 1373 SkPoint split[7]; 1374 SkChopCubicAt(pts, split, 0.5f); 1375 cubic_coverage(&split[0], distanceMap, w, h); 1376 cubic_coverage(&split[3], distanceMap, w, h); 1377 } 1378 1379 void path_coverage(const SkPath& path, uint8_t* distanceMap, int w, int h) { 1380 memset(distanceMap, 0, sizeof(distanceMap[0]) * w * h); 1381 SkPoint pts[4]; 1382 SkPath::Verb verb; 1383 SkPath::Iter iter(path, true); 1384 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { 1385 switch (verb) { 1386 case SkPath::kLine_Verb: 1387 (void) coverage(pts[0], pts[1], distanceMap, w, h); 1388 break; 1389 case SkPath::kQuad_Verb: 1390 quad_coverage(pts, distanceMap, w, h); 1391 break; 1392 case SkPath::kConic_Verb: 1393 conic_coverage(pts, iter.conicWeight(), distanceMap, w, h); 1394 break; 1395 case SkPath::kCubic_Verb: 1396 cubic_coverage(pts, distanceMap, w, h); 1397 break; 1398 default: 1399 break; 1400 } 1401 } 1402 } 1403 1404 static uint8_t* set_up_dist_map(const SkImageInfo& imageInfo, SkBitmap* distMap) { 1405 distMap->setInfo(imageInfo); 1406 distMap->setIsVolatile(true); 1407 SkAssertResult(distMap->tryAllocPixels()); 1408 SkASSERT((int) distMap->rowBytes() == imageInfo.width()); 1409 return distMap->getAddr8(0, 0); 1410 } 1411 1412 void path_stroke(int index, SkPath* inner, SkPath* outer) { 1413 #if 0 1414 SkPathStroker stroker(fPath, fWidthControl.fValLo, 0, 1415 SkPaint::kRound_Cap, SkPaint::kRound_Join, fResControl.fValLo); 1416 SkPoint pts[4], firstPt, lastPt; 1417 SkPath::Verb verb; 1418 SkPath::Iter iter(fPath, true); 1419 int counter = -1; 1420 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { 1421 ++counter; 1422 switch (verb) { 1423 case SkPath::kMove_Verb: 1424 firstPt = pts[0]; 1425 break; 1426 case SkPath::kLine_Verb: 1427 if (counter == index) { 1428 stroker.moveTo(pts[0]); 1429 stroker.lineTo(pts[1]); 1430 goto done; 1431 } 1432 lastPt = pts[1]; 1433 break; 1434 case SkPath::kQuad_Verb: 1435 if (counter == index) { 1436 stroker.moveTo(pts[0]); 1437 stroker.quadTo(pts[1], pts[2]); 1438 goto done; 1439 } 1440 lastPt = pts[2]; 1441 break; 1442 case SkPath::kConic_Verb: 1443 if (counter == index) { 1444 stroker.moveTo(pts[0]); 1445 stroker.conicTo(pts[1], pts[2], iter.conicWeight()); 1446 goto done; 1447 } 1448 lastPt = pts[2]; 1449 break; 1450 case SkPath::kCubic_Verb: 1451 if (counter == index) { 1452 stroker.moveTo(pts[0]); 1453 stroker.cubicTo(pts[1], pts[2], pts[3]); 1454 goto done; 1455 } 1456 lastPt = pts[3]; 1457 break; 1458 case SkPath::kClose_Verb: 1459 if (counter == index) { 1460 stroker.moveTo(lastPt); 1461 stroker.lineTo(firstPt); 1462 goto done; 1463 } 1464 break; 1465 case SkPath::kDone_Verb: 1466 break; 1467 default: 1468 SkASSERT(0); 1469 } 1470 } 1471 done: 1472 *inner = stroker.fInner; 1473 *outer = stroker.fOuter; 1474#endif 1475 } 1476 1477 void draw_stroke(SkCanvas* canvas, int active) { 1478 SkPath inner, outer; 1479 path_stroke(active, &inner, &outer); 1480 canvas->drawPath(inner, fSkeletonPaint); 1481 canvas->drawPath(outer, fSkeletonPaint); 1482 } 1483 1484 void gather_strokes() { 1485 fStrokes.reset(); 1486 for (int index = 0; index < fPath.countVerbs(); ++index) { 1487 Stroke& inner = fStrokes.push_back(); 1488 inner.reset(); 1489 inner.fInner = true; 1490 Stroke& outer = fStrokes.push_back(); 1491 outer.reset(); 1492 outer.fInner = false; 1493 path_stroke(index, &inner.fPath, &outer.fPath); 1494 } 1495 } 1496 1497 void trim_strokes() { 1498 // eliminate self-itersecting loops 1499 // trim outside edges 1500 gather_strokes(); 1501 for (int index = 0; index < fStrokes.count(); ++index) { 1502 SkPath& outPath = fStrokes[index].fPath; 1503 for (int inner = 0; inner < fStrokes.count(); ++inner) { 1504 if (index == inner) { 1505 continue; 1506 } 1507 SkPath& inPath = fStrokes[inner].fPath; 1508 if (!outPath.getBounds().intersects(inPath.getBounds())) { 1509 continue; 1510 } 1511 1512 } 1513 } 1514 } 1515 1516 void onDrawContent(SkCanvas* canvas) override { 1517#if 0 1518 SkDEBUGCODE(SkDebugStrokeGlobals debugGlobals); 1519 SkOpAA aaResult(fPath, fWidthControl.fValLo, fResControl.fValLo 1520 SkDEBUGPARAMS(&debugGlobals)); 1521#endif 1522 SkPath strokePath; 1523// aaResult.simplify(&strokePath); 1524 canvas->drawPath(strokePath, fSkeletonPaint); 1525 SkRect bounds = fPath.getBounds(); 1526 SkScalar radius = fWidthControl.fValLo; 1527 int w = (int) (bounds.fRight + radius + 1); 1528 int h = (int) (bounds.fBottom + radius + 1); 1529 SkImageInfo imageInfo = SkImageInfo::MakeA8(w, h); 1530 SkBitmap distMap; 1531 uint8_t* distanceMap = set_up_dist_map(imageInfo, &distMap); 1532 path_coverage(fPath, distanceMap, w, h); 1533 if (fFillButton.enabled()) { 1534 canvas->drawPath(fPath, fCoveragePaint); 1535 } 1536 if (fFilterButton.fState == 2 1537 && (0 < fFilterControl.fValLo || fFilterControl.fValHi < 255)) { 1538 SkBitmap filteredMap; 1539 uint8_t* filtered = set_up_dist_map(imageInfo, &filteredMap); 1540 filter_coverage(distanceMap, sizeof(uint8_t) * w * h, (uint8_t) fFilterControl.fValLo, 1541 (uint8_t) fFilterControl.fValHi, filtered); 1542 canvas->drawBitmap(filteredMap, 0, 0, &fCoveragePaint); 1543 } else if (fFilterButton.enabled()) { 1544 canvas->drawBitmap(distMap, 0, 0, &fCoveragePaint); 1545 } 1546 if (fSkeletonButton.enabled()) { 1547 canvas->drawPath(fPath, fActiveVerb >= 0 ? fLightSkeletonPaint : fSkeletonPaint); 1548 } 1549 if (fActiveVerb >= 0) { 1550 draw_segment(canvas); 1551 } 1552 if (fBisectButton.enabled() || fJoinButton.enabled()) { 1553 draw_bisects(canvas, fActiveVerb >= 0); 1554 } 1555 if (fInOutButton.enabled()) { 1556 if (fActiveVerb >= 0) { 1557 draw_stroke(canvas, fActiveVerb); 1558 } else { 1559 for (int index = 0; index < fPath.countVerbs(); ++index) { 1560 draw_stroke(canvas, index); 1561 } 1562 } 1563 } 1564 if (fHideAll) { 1565 return; 1566 } 1567 for (int index = 0; index < kControlCount; ++index) { 1568 kControlList[index].fControl->draw(canvas, fControlPaints); 1569 } 1570 for (int index = 0; index < kButtonCount; ++index) { 1571 kButtonList[index].fButton->draw(canvas, fButtonPaints); 1572 } 1573 if (fShowLegend) { 1574 draw_legend(canvas); 1575 } 1576 1577#if 0 1578 SkPaint paint; 1579 paint.setARGB(255, 34, 31, 31); 1580 paint.setAntiAlias(true); 1581 1582 SkPath path; 1583 path.moveTo(18,439); 1584 path.lineTo(414,439); 1585 path.lineTo(414,702); 1586 path.lineTo(18,702); 1587 path.lineTo(18,439); 1588 1589 path.moveTo(19,701); 1590 path.lineTo(413,701); 1591 path.lineTo(413,440); 1592 path.lineTo(19,440); 1593 path.lineTo(19,701); 1594 path.close(); 1595 canvas->drawPath(path, paint); 1596 1597 canvas->scale(1.0f, -1.0f); 1598 canvas->translate(0.0f, -800.0f); 1599 canvas->drawPath(path, paint); 1600#endif 1601 1602 } 1603 1604 int hittest_pt(SkPoint pt) { 1605 for (int index = 0; index < fPath.countPoints(); ++index) { 1606 if (SkPoint::Distance(fPath.getPoint(index), pt) <= kHitToleranace * 2) { 1607 return index; 1608 } 1609 } 1610 return -1; 1611 } 1612 1613 virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) override { 1614 SkPoint pt = {x, y}; 1615 int ptHit = hittest_pt(pt); 1616 if (ptHit >= 0) { 1617 return new MyClick(this, MyClick::kPtType, ptHit); 1618 } 1619 SkPath::Verb verb; 1620 SkScalar weight; 1621 int verbHit = hittest_verb(pt, &verb, &weight); 1622 if (verbHit >= 0) { 1623 return new MyClick(this, MyClick::kVerbType, verbHit, verb, weight); 1624 } 1625 if (!fHideAll) { 1626 const SkRect& rectPt = SkRect::MakeXYWH(x, y, 1, 1); 1627 for (int index = 0; index < kControlCount; ++index) { 1628 if (kControlList[index].fControl->contains(rectPt)) { 1629 return new MyClick(this, MyClick::kControlType, 1630 kControlList[index].fControlType); 1631 } 1632 } 1633 for (int index = 0; index < kButtonCount; ++index) { 1634 if (kButtonList[index].fButton->contains(rectPt)) { 1635 return new MyClick(this, MyClick::kControlType, kButtonList[index].fButtonType); 1636 } 1637 } 1638 } 1639 fLineButton.fVisible = fQuadButton.fVisible = fConicButton.fVisible 1640 = fCubicButton.fVisible = fWeightControl.fVisible = fAddButton.fVisible 1641 = fDeleteButton.fVisible = false; 1642 fActiveVerb = -1; 1643 fActivePt = -1; 1644 if (fHandlePathMove) { 1645 return new MyClick(this, MyClick::kPathType, MyClick::kPathMove); 1646 } 1647 return this->INHERITED::onFindClickHandler(x, y, modi); 1648 } 1649 1650 static SkScalar MapScreenYtoValue(int y, const UniControl& control) { 1651 return SkTMin(1.f, SkTMax(0.f, 1652 SkIntToScalar(y) - control.fBounds.fTop) / control.fBounds.height()) 1653 * (control.fMax - control.fMin) + control.fMin; 1654 } 1655 1656 bool onClick(Click* click) override { 1657 MyClick* myClick = (MyClick*) click; 1658 switch (myClick->fType) { 1659 case MyClick::kPtType: { 1660 savePath(click->fState); 1661 fActivePt = myClick->ptHit(); 1662 SkPoint pt = fPath.getPoint((int) myClick->fControl); 1663 pt.offset(SkIntToScalar(click->fICurr.fX - click->fIPrev.fX), 1664 SkIntToScalar(click->fICurr.fY - click->fIPrev.fY)); 1665 set_path_pt(fActivePt, pt, &fPath); 1666 validatePath(); 1667 return true; 1668 } 1669 case MyClick::kPathType: 1670 savePath(click->fState); 1671 fPath.offset(SkIntToScalar(click->fICurr.fX - click->fIPrev.fX), 1672 SkIntToScalar(click->fICurr.fY - click->fIPrev.fY)); 1673 validatePath(); 1674 return true; 1675 case MyClick::kVerbType: { 1676 fActiveVerb = myClick->verbHit(); 1677 fLineButton.fVisible = fQuadButton.fVisible = fConicButton.fVisible 1678 = fCubicButton.fVisible = fAddButton.fVisible = fDeleteButton.fVisible 1679 = true; 1680 fLineButton.setEnabled(myClick->fVerb == SkPath::kLine_Verb); 1681 fQuadButton.setEnabled(myClick->fVerb == SkPath::kQuad_Verb); 1682 fConicButton.setEnabled(myClick->fVerb == SkPath::kConic_Verb); 1683 fCubicButton.setEnabled(myClick->fVerb == SkPath::kCubic_Verb); 1684 fWeightControl.fValLo = myClick->fWeight; 1685 fWeightControl.fVisible = myClick->fVerb == SkPath::kConic_Verb; 1686 } break; 1687 case MyClick::kControlType: { 1688 if (click->fState != Click::kDown_State && myClick->isButton()) { 1689 return true; 1690 } 1691 switch (myClick->fControl) { 1692 case MyClick::kFilterControl: { 1693 SkScalar val = MapScreenYtoValue(click->fICurr.fY, fFilterControl); 1694 if (val - fFilterControl.fValLo < fFilterControl.fValHi - val) { 1695 fFilterControl.fValLo = SkTMax(0.f, val); 1696 } else { 1697 fFilterControl.fValHi = SkTMin(255.f, val); 1698 } 1699 } break; 1700 case MyClick::kResControl: 1701 fResControl.fValLo = MapScreenYtoValue(click->fICurr.fY, fResControl); 1702 break; 1703 case MyClick::kWeightControl: { 1704 savePath(click->fState); 1705 SkScalar w = MapScreenYtoValue(click->fICurr.fY, fWeightControl); 1706 set_path_weight(fActiveVerb, w, &fPath); 1707 validatePath(); 1708 fWeightControl.fValLo = w; 1709 } break; 1710 case MyClick::kWidthControl: 1711 fWidthControl.fValLo = MapScreenYtoValue(click->fICurr.fY, fWidthControl); 1712 break; 1713 case MyClick::kLineButton: 1714 savePath(click->fState); 1715 enable_verb_button(myClick->fControl); 1716 fWeightControl.fVisible = false; 1717 set_path_verb(fActiveVerb, SkPath::kLine_Verb, &fPath, 1); 1718 validatePath(); 1719 break; 1720 case MyClick::kQuadButton: 1721 savePath(click->fState); 1722 enable_verb_button(myClick->fControl); 1723 fWeightControl.fVisible = false; 1724 set_path_verb(fActiveVerb, SkPath::kQuad_Verb, &fPath, 1); 1725 validatePath(); 1726 break; 1727 case MyClick::kConicButton: { 1728 savePath(click->fState); 1729 enable_verb_button(myClick->fControl); 1730 fWeightControl.fVisible = true; 1731 const SkScalar defaultConicWeight = 1.f / SkScalarSqrt(2); 1732 set_path_verb(fActiveVerb, SkPath::kConic_Verb, &fPath, defaultConicWeight); 1733 validatePath(); 1734 fWeightControl.fValLo = get_path_weight(fActiveVerb, fPath); 1735 } break; 1736 case MyClick::kCubicButton: 1737 savePath(click->fState); 1738 enable_verb_button(myClick->fControl); 1739 fWeightControl.fVisible = false; 1740 set_path_verb(fActiveVerb, SkPath::kCubic_Verb, &fPath, 1); 1741 validatePath(); 1742 break; 1743 case MyClick::kAddButton: 1744 savePath(click->fState); 1745 add_path_segment(fActiveVerb, &fPath); 1746 validatePath(); 1747 if (fWeightControl.fVisible) { 1748 fWeightControl.fValLo = get_path_weight(fActiveVerb, fPath); 1749 } 1750 break; 1751 case MyClick::kDeleteButton: 1752 savePath(click->fState); 1753 delete_path_segment(fActiveVerb, &fPath); 1754 validatePath(); 1755 break; 1756 case MyClick::kFillButton: 1757 fFillButton.toggle(); 1758 break; 1759 case MyClick::kSkeletonButton: 1760 fSkeletonButton.toggle(); 1761 break; 1762 case MyClick::kFilterButton: 1763 fFilterButton.toggle(); 1764 fFilterControl.fVisible = fFilterButton.fState == 2; 1765 break; 1766 case MyClick::kBisectButton: 1767 fBisectButton.toggle(); 1768 break; 1769 case MyClick::kJoinButton: 1770 fJoinButton.toggle(); 1771 break; 1772 case MyClick::kInOutButton: 1773 fInOutButton.toggle(); 1774 break; 1775 default: 1776 SkASSERT(0); 1777 break; 1778 } 1779 } break; 1780 default: 1781 SkASSERT(0); 1782 break; 1783 } 1784 setControlButtonsPos(); 1785 return true; 1786 } 1787 1788private: 1789 typedef SampleView INHERITED; 1790}; 1791 1792static struct KeyCommand { 1793 char fKey; 1794 char fAlternate; 1795 const char* fDescriptionL; 1796 const char* fDescriptionR; 1797 bool (AAGeometryView::*fFunction)(); 1798} kKeyCommandList[] = { 1799 { ' ', 0, "space", "center path", &AAGeometryView::scaleToFit }, 1800 { '-', 0, "-", "zoom out", &AAGeometryView::scaleDown }, 1801 { '+', '=', "+/=", "zoom in", &AAGeometryView::scaleUp }, 1802 { 'D', 0, "D", "dump to console", &AAGeometryView::pathDump }, 1803 { 'H', 0, "H", "hide controls", &AAGeometryView::hideAll }, 1804 { 'R', 0, "R", "reset path", &AAGeometryView::constructPath }, 1805 { 'Z', 0, "Z", "undo", &AAGeometryView::undo }, 1806 { '?', 0, "?", "show legend", &AAGeometryView::showLegend }, 1807}; 1808 1809const int kKeyCommandCount = (int) SK_ARRAY_COUNT(kKeyCommandList); 1810 1811void AAGeometryView::draw_legend(SkCanvas* canvas) { 1812 SkScalar bottomOffset = this->height() - 10; 1813 for (int index = kKeyCommandCount - 1; index >= 0; --index) { 1814 bottomOffset -= 15; 1815 canvas->drawString(kKeyCommandList[index].fDescriptionL, 1816 this->width() - 160, bottomOffset, 1817 fLegendLeftPaint); 1818 canvas->drawString(kKeyCommandList[index].fDescriptionR, 1819 this->width() - 20, bottomOffset, 1820 fLegendRightPaint); 1821 } 1822} 1823 1824// overrides from SkEventSink 1825bool AAGeometryView::onQuery(SkEvent* evt) { 1826 if (SampleCode::TitleQ(*evt)) { 1827 SampleCode::TitleR(evt, "AAGeometry"); 1828 return true; 1829 } 1830 SkUnichar uni; 1831 if (false) { 1832 return this->INHERITED::onQuery(evt); 1833 } 1834 if (SampleCode::CharQ(*evt, &uni)) { 1835 for (int index = 0; index < kButtonCount; ++index) { 1836 Button* button = kButtonList[index].fButton; 1837 if (button->fVisible && uni == button->fLabel) { 1838 MyClick click(this, MyClick::kControlType, kButtonList[index].fButtonType); 1839 click.fState = Click::kDown_State; 1840 (void) this->onClick(&click); 1841 return true; 1842 } 1843 } 1844 for (int index = 0; index < kKeyCommandCount; ++index) { 1845 KeyCommand& keyCommand = kKeyCommandList[index]; 1846 if (uni == keyCommand.fKey || uni == keyCommand.fAlternate) { 1847 return (this->*keyCommand.fFunction)(); 1848 } 1849 } 1850 if (('A' <= uni && uni <= 'Z') || ('a' <= uni && uni <= 'z')) { 1851 for (int index = 0; index < kButtonCount; ++index) { 1852 Button* button = kButtonList[index].fButton; 1853 if (button->fVisible && (uni & ~0x20) == (button->fLabel & ~0x20)) { 1854 MyClick click(this, MyClick::kControlType, kButtonList[index].fButtonType); 1855 click.fState = Click::kDown_State; 1856 (void) this->onClick(&click); 1857 return true; 1858 } 1859 } 1860 } 1861 } 1862 return this->INHERITED::onQuery(evt); 1863} 1864 1865DEF_SAMPLE( return new AAGeometryView; ) 1866