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