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