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