• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
21 void 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 
33 void SkStrokeSegment::dumpAll() const {
34     const SkStrokeSegment* segment = this;
35     while (segment) {
36         segment->dump();
37         segment = segment->fNext;
38     }
39 }
40 
41 void 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 
63 void SkStrokeTriple::dumpAll() const {
64     const SkStrokeTriple* triple = this;
65     while (triple) {
66         triple->dump();
67         triple = triple->fNext;
68     }
69 }
70 
71 void 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 
83 void SkStrokeContour::dumpAll() const {
84     const SkStrokeContour* contour = this;
85     while (contour) {
86         contour->dump();
87         contour = contour->fNext;
88     }
89 }
90 #endif
91 
92 SkScalar gCurveDistance = 10;
93 
94 #if 0  // unused
95 static 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 
get_path_weight(int index,const SkPath & path)114 static 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 
set_path_pt(int index,const SkPoint & pt,SkPath * path)129 static 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 
add_path_segment(int index,SkPath * path)201 static 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 
delete_path_segment(int index,SkPath * path)277 static 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 
set_path_weight(int index,SkScalar w,SkPath * path)315 static 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 
set_path_verb(int index,SkPath::Verb v,SkPath * path,SkScalar w)351 static 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 
add_to_map(SkScalar coverage,int x,int y,uint8_t * distanceMap,int w,int h)459 static 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 
filter_coverage(const uint8_t * map,int len,uint8_t min,uint8_t max,uint8_t * filter)471 static 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 
construct_path(SkPath & path)479 static 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 
489 struct ButtonPaints {
490     static const int kMaxStateCount = 3;
491     SkPaint fDisabled;
492     SkPaint fStates[kMaxStateCount];
493     SkPaint fLabel;
494 
ButtonPaintsButtonPaints495     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 
510 struct Button {
511     SkRect fBounds;
512     int fStateCount;
513     int fState;
514     char fLabel;
515     bool fVisible;
516 
ButtonButton517     Button(char label) {
518         fStateCount = 2;
519         fState = 0;
520         fLabel = label;
521         fVisible = false;
522     }
523 
ButtonButton524     Button(char label, int stateCount) {
525         SkASSERT(stateCount <= ButtonPaints::kMaxStateCount);
526         fStateCount = stateCount;
527         fState = 0;
528         fLabel = label;
529         fVisible = false;
530     }
531 
containsButton532     bool contains(const SkRect& rect) {
533         return fVisible && fBounds.contains(rect);
534     }
535 
enabledButton536     bool enabled() {
537         return SkToBool(fState);
538     }
539 
drawButton540     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 
toggleButton548     void toggle() {
549         if (++fState == fStateCount) {
550             fState = 0;
551         }
552     }
553 
setEnabledButton554     void setEnabled(bool enabled) {
555         fState = (int) enabled;
556     }
557 };
558 
559 struct ControlPaints {
560     SkPaint fOutline;
561     SkPaint fIndicator;
562     SkPaint fFill;
563     SkPaint fLabel;
564     SkPaint fValue;
565 
ControlPaintsControlPaints566     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 
580 struct UniControl {
581     SkString fName;
582     SkRect fBounds;
583     SkScalar fMin;
584     SkScalar fMax;
585     SkScalar fValLo;
586     SkScalar fYLo;
587     bool fVisible;
588 
UniControlUniControl589     UniControl(const char* name, SkScalar min, SkScalar max) {
590         fName = name;
591         fValLo =  fMin = min;
592         fMax = max;
593         fVisible = false;
594 
595     }
596 
~UniControlUniControl597     virtual ~UniControl() {}
598 
containsUniControl599     bool contains(const SkRect& rect) {
600         return fVisible && fBounds.contains(rect);
601     }
602 
drawUniControl603     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 
618 struct BiControl : public UniControl {
619     SkScalar fValHi;
620 
BiControlBiControl621     BiControl(const char* name, SkScalar min, SkScalar max)
622         : UniControl(name, min, max)
623         ,  fValHi(fMax) {
624     }
625 
~BiControlBiControl626     virtual ~BiControl() {}
627 
drawBiControl628     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 
647 class MyClick : public SampleView::Click {
648 public:
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 
MyClick(SkView * target,ClickType type,ControlType control)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 
MyClick(SkView * target,ClickType type,int index)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 
MyClick(SkView * target,ClickType type,int index,SkPath::Verb verb,SkScalar weight)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 
isButton()710     bool isButton() {
711         return kFirstButton <= fControl && fControl <= kLastButton;
712     }
713 
ptHit() const714     int ptHit() const {
715         SkASSERT(fType == kPtType);
716         return (int) fControl;
717     }
718 
verbHit() const719     int verbHit() const {
720         SkASSERT(fType == kVerbType);
721         return (int) fControl;
722     }
723 };
724 
725 enum {
726     kControlCount = MyClick::kLastControl - MyClick::kFirstControl + 1,
727 };
728 
729 static struct ControlPair {
730     UniControl* fControl;
731     MyClick::ControlType fControlType;
732 } kControlList[kControlCount];
733 
734 enum {
735     kButtonCount = MyClick::kLastButton - MyClick::kFirstButton + 1,
736     kVerbCount = MyClick::kLastVerbButton - MyClick::kFirstButton + 1,
737 };
738 
739 static struct ButtonPair {
740     Button* fButton;
741     MyClick::ControlType fButtonType;
742 } kButtonList[kButtonCount];
743 
enable_verb_button(MyClick::ControlType type)744 static 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 
754 struct Stroke;
755 
756 struct Active {
757     Active* fNext;
758     Stroke* fParent;
759     SkScalar fStart;
760     SkScalar fEnd;
761 
resetActive762     void reset() {
763         fNext = nullptr;
764         fStart = 0;
765         fEnd = 1;
766     }
767 };
768 
769 struct Stroke {
770     SkPath fPath;
771     Active fActive;
772     bool fInner;
773 
resetStroke774     void reset() {
775         fPath.reset();
776         fActive.reset();
777     }
778 };
779 
780 struct PathUndo {
781     SkPath fPath;
782     PathUndo* fNext;
783 };
784 
785 class 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 
822 public:
823 
AAGeometryView()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 
constructPath()885     bool constructPath() {
886         construct_path(fPath);
887         return true;
888     }
889 
savePath(Click::State state)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 
undo()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 
validatePath()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 
set_controlList(int index,UniControl * control,MyClick::ControlType type)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 
hideAll()932     bool hideAll() {
933         fHideAll ^= true;
934         return true;
935     }
936 
init_controlList()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 
set_buttonList(int index,Button * button,MyClick::ControlType type)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 
init_buttonList()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 
onSizeChange()976     void onSizeChange() override {
977         setControlButtonsPos();
978         this->INHERITED::onSizeChange();
979     }
980 
pathDump()981     bool pathDump() {
982         fPath.dump();
983         return true;
984     }
985 
scaleDown()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 
scaleToFit()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 
scaleUp()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 
setControlButtonsPos()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 
showLegend()1034     bool showLegend() {
1035         fShowLegend ^= true;
1036         return true;
1037     }
1038 
draw_bisect(SkCanvas * canvas,const SkVector & lastVector,const SkVector & vector,const SkPoint & pt)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 
draw_bisects(SkCanvas * canvas,bool activeOnly)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 
draw_segment(SkCanvas * canvas)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 
draw_points(SkCanvas * canvas,SkPoint * points,int count)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 
hittest_verb(SkPoint pt,SkPath::Verb * verbPtr,SkScalar * weight)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 
pt_to_line(SkPoint s,SkPoint e,int x,int y)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
coverage(SkPoint s,SkPoint e,uint8_t * distanceMap,int w,int h)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 
quad_coverage(SkPoint pts[3],uint8_t * distanceMap,int w,int h)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 
conic_coverage(SkPoint pts[3],SkScalar weight,uint8_t * distanceMap,int w,int h)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 
cubic_coverage(SkPoint pts[4],uint8_t * distanceMap,int w,int h)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 
path_coverage(const SkPath & path,uint8_t * distanceMap,int w,int h)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 
set_up_dist_map(const SkImageInfo & imageInfo,SkBitmap * distMap)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 
path_stroke(int index,SkPath * inner,SkPath * outer)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 
draw_stroke(SkCanvas * canvas,int active)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 
gather_strokes()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 
trim_strokes()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 
onDrawContent(SkCanvas * canvas)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 
hittest_pt(SkPoint pt)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 
onFindClickHandler(SkScalar x,SkScalar y,unsigned modi)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 
MapScreenYtoValue(int y,const UniControl & control)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 
onClick(Click * click)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 
1788 private:
1789     typedef SampleView INHERITED;
1790 };
1791 
1792 static 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 
1809 const int kKeyCommandCount = (int) SK_ARRAY_COUNT(kKeyCommandList);
1810 
draw_legend(SkCanvas * canvas)1811 void 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
onQuery(SkEvent * evt)1825 bool 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 
1865 DEF_SAMPLE( return new AAGeometryView; )
1866