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