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