blob: ac9ffc9122d9b27ea6e3a9fe1f46e719c67b1c26 [file] [log] [blame]
caryclark63c684a2015-02-25 09:04:04 -08001/*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SampleCode.h"
9#include "SkView.h"
10#include "SkCanvas.h"
11#include "SkPaint.h"
12#include "SkPath.h"
13#include "SkMatrix.h"
14#include "SkColor.h"
15#include "SkTDArray.h"
16#include "SkRandom.h"
bungemand3ebb482015-08-05 13:57:49 -070017#include "SkRRect.h"
caryclark63c684a2015-02-25 09:04:04 -080018
19enum RandomAddPath {
20 kMoveToPath,
21 kRMoveToPath,
22 kLineToPath,
23 kRLineToPath,
24 kQuadToPath,
25 kRQuadToPath,
26 kConicToPath,
27 kRConicToPath,
28 kCubicToPath,
29 kRCubicToPath,
30 kArcToPath,
31 kArcTo2Path,
32 kClosePath,
33 kAddArc,
34 kAddRoundRect1,
35 kAddRoundRect2,
36 kAddRRect,
37 kAddPoly,
38 kAddPath1,
39 kAddPath2,
40 kAddPath3,
41 kReverseAddPath,
42};
43
44const int kRandomAddPath_Last = kReverseAddPath;
45
46const char* gRandomAddPathNames[] = {
47 "kMoveToPath",
48 "kRMoveToPath",
49 "kLineToPath",
50 "kRLineToPath",
51 "kQuadToPath",
52 "kRQuadToPath",
53 "kConicToPath",
54 "kRConicToPath",
55 "kCubicToPath",
56 "kRCubicToPath",
57 "kArcToPath",
58 "kArcTo2Path",
59 "kClosePath",
60 "kAddArc",
61 "kAddRoundRect1",
62 "kAddRoundRect2",
63 "kAddRRect",
64 "kAddPoly",
65 "kAddPath1",
66 "kAddPath2",
67 "kAddPath3",
68 "kReverseAddPath",
69};
70
71enum RandomSetRRect {
72 kSetEmpty,
73 kSetRect,
74 kSetOval,
75 kSetRectXY,
76 kSetNinePatch,
77 kSetRectRadii,
78};
79
80const char* gRandomSetRRectNames[] = {
81 "kSetEmpty",
82 "kSetRect",
83 "kSetOval",
84 "kSetRectXY",
85 "kSetNinePatch",
86 "kSetRectRadii",
87};
88
89int kRandomSetRRect_Last = kSetRectRadii;
90
91enum RandomSetMatrix {
92 kSetIdentity,
93 kSetTranslate,
94 kSetTranslateX,
95 kSetTranslateY,
96 kSetScale,
97 kSetScaleTranslate,
98 kSetScaleX,
99 kSetScaleY,
100 kSetSkew,
101 kSetSkewTranslate,
102 kSetSkewX,
103 kSetSkewY,
104 kSetRotate,
105 kSetRotateTranslate,
106 kSetPerspectiveX,
107 kSetPerspectiveY,
108 kSetAll,
109};
110
111int kRandomSetMatrix_Last = kSetAll;
112
113const char* gRandomSetMatrixNames[] = {
114 "kSetIdentity",
115 "kSetTranslate",
116 "kSetTranslateX",
117 "kSetTranslateY",
118 "kSetScale",
119 "kSetScaleTranslate",
120 "kSetScaleX",
121 "kSetScaleY",
122 "kSetSkew",
123 "kSetSkewTranslate",
124 "kSetSkewX",
125 "kSetSkewY",
126 "kSetRotate",
127 "kSetRotateTranslate",
128 "kSetPerspectiveX",
129 "kSetPerspectiveY",
130 "kSetAll",
131};
132
133class FuzzPath {
134public:
caryclark94b4ee82015-03-04 12:32:22 -0800135 FuzzPath()
caryclark63c684a2015-02-25 09:04:04 -0800136 : fFloatMin(0)
137 , fFloatMax(800)
138 , fAddCount(0)
139 , fPrintName(false)
caryclark94b4ee82015-03-04 12:32:22 -0800140 , fStrokeOnly(false)
caryclark63c684a2015-02-25 09:04:04 -0800141 , fValidate(false)
142 {
143 fTab = " ";
144 }
145 void randomize() {
146 fPathDepth = 0;
147 fPathDepthLimit = fRand.nextRangeU(1, 2);
148 fPathContourCount = fRand.nextRangeU(1, 4);
149 fPathSegmentLimit = fRand.nextRangeU(1, 8);
150 fClip = makePath();
151 SkASSERT(!fPathDepth);
152 fMatrix = makeMatrix();
153 fPaint = makePaint();
154 fPathDepthLimit = fRand.nextRangeU(1, 3);
155 fPathContourCount = fRand.nextRangeU(1, 6);
156 fPathSegmentLimit = fRand.nextRangeU(1, 16);
157 fPath = makePath();
158 SkASSERT(!fPathDepth);
159 }
160
161 const SkPath& getClip() const {
162 return fClip;
163 }
164
165 const SkMatrix& getMatrix() const {
166 return fMatrix;
167 }
168
169 const SkPaint& getPaint() const {
170 return fPaint;
171 }
172
173 const SkPath& getPath() const {
174 return fPath;
175 }
176
caryclark94b4ee82015-03-04 12:32:22 -0800177 void setSeed(int seed) {
178 fRand.setSeed(seed);
179 }
180
181 void setStrokeOnly() {
182 fStrokeOnly = true;
183 }
184
caryclark63c684a2015-02-25 09:04:04 -0800185private:
186
187SkPath::AddPathMode makeAddPathMode() {
188 return (SkPath::AddPathMode) fRand.nextRangeU(SkPath::kAppend_AddPathMode,
189 SkPath::kExtend_AddPathMode);
190}
191
192RandomAddPath makeAddPathType() {
193 return (RandomAddPath) fRand.nextRangeU(0, kRandomAddPath_Last);
194}
195
196SkScalar makeAngle() {
197 SkScalar angle;
198 angle = fRand.nextF();
199 return angle;
200}
201
202bool makeBool() {
203 return fRand.nextBool();
204}
205
206SkPath::Direction makeDirection() {
207 return (SkPath::Direction) fRand.nextRangeU(SkPath::kCW_Direction, SkPath::kCCW_Direction);
208}
209
210SkMatrix makeMatrix() {
211 SkMatrix matrix;
212 matrix.reset();
213 RandomSetMatrix setMatrix = (RandomSetMatrix) fRand.nextRangeU(0, kRandomSetMatrix_Last);
214 if (fPrintName) {
215 SkDebugf("%.*s%s\n", fPathDepth * 3, fTab, gRandomSetMatrixNames[setMatrix]);
216 }
217 switch (setMatrix) {
218 case kSetIdentity:
219 break;
220 case kSetTranslateX:
221 matrix.setTranslateX(makeScalar());
222 break;
223 case kSetTranslateY:
224 matrix.setTranslateY(makeScalar());
225 break;
226 case kSetTranslate:
227 matrix.setTranslate(makeScalar(), makeScalar());
228 break;
229 case kSetScaleX:
230 matrix.setScaleX(makeScalar());
231 break;
232 case kSetScaleY:
233 matrix.setScaleY(makeScalar());
234 break;
235 case kSetScale:
236 matrix.setScale(makeScalar(), makeScalar());
237 break;
238 case kSetScaleTranslate:
239 matrix.setScale(makeScalar(), makeScalar(), makeScalar(), makeScalar());
240 break;
241 case kSetSkewX:
242 matrix.setSkewX(makeScalar());
243 break;
244 case kSetSkewY:
245 matrix.setSkewY(makeScalar());
246 break;
247 case kSetSkew:
248 matrix.setSkew(makeScalar(), makeScalar());
249 break;
250 case kSetSkewTranslate:
251 matrix.setSkew(makeScalar(), makeScalar(), makeScalar(), makeScalar());
252 break;
253 case kSetRotate:
254 matrix.setRotate(makeScalar());
255 break;
256 case kSetRotateTranslate:
257 matrix.setRotate(makeScalar(), makeScalar(), makeScalar());
258 break;
259 case kSetPerspectiveX:
260 matrix.setPerspX(makeScalar());
261 break;
262 case kSetPerspectiveY:
263 matrix.setPerspY(makeScalar());
264 break;
265 case kSetAll:
266 matrix.setAll(makeScalar(), makeScalar(), makeScalar(),
267 makeScalar(), makeScalar(), makeScalar(),
268 makeScalar(), makeScalar(), makeScalar());
269 break;
270 }
271 return matrix;
272}
273
274SkPaint makePaint() {
275 SkPaint paint;
276 bool antiAlias = fRand.nextBool();
277 paint.setAntiAlias(antiAlias);
caryclark94b4ee82015-03-04 12:32:22 -0800278 SkPaint::Style style = fStrokeOnly ? SkPaint::kStroke_Style :
279 (SkPaint::Style) fRand.nextRangeU(SkPaint::kFill_Style, SkPaint::kStrokeAndFill_Style);
caryclark63c684a2015-02-25 09:04:04 -0800280 paint.setStyle(style);
281 SkColor color = (SkColor) fRand.nextU();
282 paint.setColor(color);
caryclark94b4ee82015-03-04 12:32:22 -0800283 SkScalar width = fRand.nextRangeF(0, 10);
caryclark63c684a2015-02-25 09:04:04 -0800284 paint.setStrokeWidth(width);
caryclark94b4ee82015-03-04 12:32:22 -0800285 SkScalar miter = makeScalar();
caryclark63c684a2015-02-25 09:04:04 -0800286 paint.setStrokeMiter(miter);
287 SkPaint::Cap cap = (SkPaint::Cap) fRand.nextRangeU(SkPaint::kButt_Cap, SkPaint::kSquare_Cap);
288 paint.setStrokeCap(cap);
289 SkPaint::Join join = (SkPaint::Join) fRand.nextRangeU(SkPaint::kMiter_Join,
290 SkPaint::kBevel_Join);
291 paint.setStrokeJoin(join);
292 return paint;
293}
294
295SkPoint makePoint() {
296 SkPoint result;
297 makeScalarArray(2, &result.fX);
298 return result;
299}
300
301void makePointArray(size_t arrayCount, SkPoint* points) {
302 for (size_t index = 0; index < arrayCount; ++index) {
303 points[index] = makePoint();
304 }
305}
306
307void makePointArray(SkTDArray<SkPoint>* points) {
308 size_t arrayCount = fRand.nextRangeU(1, 10);
309 for (size_t index = 0; index < arrayCount; ++index) {
310 *points->append() = makePoint();
311 }
312}
313
314SkRect makeRect() {
315 SkRect result;
316 makeScalarArray(4, &result.fLeft);
317 return result;
318}
319
320SkRRect makeRRect() {
321 SkRRect rrect;
322 RandomSetRRect rrectType = makeSetRRectType();
323 if (fPrintName) {
324 SkDebugf("%.*s%s\n", fPathDepth * 3, fTab, gRandomSetRRectNames[rrectType]);
325 }
326 switch (rrectType) {
327 case kSetEmpty:
328 rrect.setEmpty();
329 break;
330 case kSetRect: {
331 SkRect rect = makeRect();
332 rrect.setRect(rect);
333 } break;
334 case kSetOval: {
335 SkRect oval = makeRect();
336 rrect.setOval(oval);
337 } break;
338 case kSetRectXY: {
339 SkRect rect = makeRect();
340 SkScalar xRad = makeScalar();
341 SkScalar yRad = makeScalar();
342 rrect.setRectXY(rect, xRad, yRad);
343 } break;
344 case kSetNinePatch: {
345 SkRect rect = makeRect();
346 SkScalar leftRad = makeScalar();
347 SkScalar topRad = makeScalar();
348 SkScalar rightRad = makeScalar();
349 SkScalar bottomRad = makeScalar();
350 rrect.setNinePatch(rect, leftRad, topRad, rightRad, bottomRad);
351 SkDebugf(""); // keep locals in scope
352 } break;
353 case kSetRectRadii: {
354 SkRect rect = makeRect();
355 SkVector radii[4];
356 makeVectorArray(SK_ARRAY_COUNT(radii), radii);
357 rrect.setRectRadii(rect, radii);
358 } break;
359 }
360 return rrect;
361}
362
363SkPath makePath() {
364 SkPath path;
365 for (uint32_t cIndex = 0; cIndex < fPathContourCount; ++cIndex) {
366 uint32_t segments = makeSegmentCount();
367 for (uint32_t sIndex = 0; sIndex < segments; ++sIndex) {
368 RandomAddPath addPathType = makeAddPathType();
369 ++fAddCount;
370 if (fPrintName) {
371 SkDebugf("%.*s%s\n", fPathDepth * 3, fTab,
372 gRandomAddPathNames[addPathType]);
373 }
374 switch (addPathType) {
375 case kAddArc: {
376 SkRect oval = makeRect();
377 SkScalar startAngle = makeAngle();
378 SkScalar sweepAngle = makeAngle();
379 path.addArc(oval, startAngle, sweepAngle);
380 validate(path);
381 } break;
382 case kAddRoundRect1: {
383 SkRect rect = makeRect();
384 SkScalar rx = makeScalar(), ry = makeScalar();
385 SkPath::Direction dir = makeDirection();
386 path.addRoundRect(rect, rx, ry, dir);
387 validate(path);
388 } break;
389 case kAddRoundRect2: {
390 SkRect rect = makeRect();
391 SkScalar radii[8];
392 makeScalarArray(SK_ARRAY_COUNT(radii), radii);
393 SkPath::Direction dir = makeDirection();
394 path.addRoundRect(rect, radii, dir);
395 validate(path);
396 } break;
397 case kAddRRect: {
398 SkRRect rrect = makeRRect();
399 SkPath::Direction dir = makeDirection();
400 path.addRRect(rrect, dir);
401 validate(path);
402 } break;
403 case kAddPoly: {
404 SkTDArray<SkPoint> points;
405 makePointArray(&points);
406 bool close = makeBool();
407 path.addPoly(&points[0], points.count(), close);
408 validate(path);
409 } break;
410 case kAddPath1:
411 if (fPathDepth < fPathDepthLimit) {
412 ++fPathDepth;
413 SkPath src = makePath();
414 validate(src);
415 SkScalar dx = makeScalar();
416 SkScalar dy = makeScalar();
417 SkPath::AddPathMode mode = makeAddPathMode();
418 path.addPath(src, dx, dy, mode);
419 --fPathDepth;
420 validate(path);
caryclark94b4ee82015-03-04 12:32:22 -0800421 }
caryclark63c684a2015-02-25 09:04:04 -0800422 break;
423 case kAddPath2:
424 if (fPathDepth < fPathDepthLimit) {
425 ++fPathDepth;
426 SkPath src = makePath();
427 validate(src);
428 SkPath::AddPathMode mode = makeAddPathMode();
429 path.addPath(src, mode);
430 --fPathDepth;
431 validate(path);
432 }
433 break;
434 case kAddPath3:
435 if (fPathDepth < fPathDepthLimit) {
436 ++fPathDepth;
437 SkPath src = makePath();
438 validate(src);
439 SkMatrix matrix = makeMatrix();
440 SkPath::AddPathMode mode = makeAddPathMode();
441 path.addPath(src, matrix, mode);
442 --fPathDepth;
443 validate(path);
444 }
445 break;
446 case kReverseAddPath:
447 if (fPathDepth < fPathDepthLimit) {
448 ++fPathDepth;
449 SkPath src = makePath();
450 validate(src);
451 path.reverseAddPath(src);
452 --fPathDepth;
453 validate(path);
454 }
455 break;
456 case kMoveToPath: {
457 SkScalar x = makeScalar();
458 SkScalar y = makeScalar();
459 path.moveTo(x, y);
460 validate(path);
461 } break;
462 case kRMoveToPath: {
463 SkScalar x = makeScalar();
464 SkScalar y = makeScalar();
465 path.rMoveTo(x, y);
466 validate(path);
467 } break;
468 case kLineToPath: {
469 SkScalar x = makeScalar();
470 SkScalar y = makeScalar();
471 path.lineTo(x, y);
472 validate(path);
473 } break;
474 case kRLineToPath: {
475 SkScalar x = makeScalar();
476 SkScalar y = makeScalar();
477 path.rLineTo(x, y);
478 validate(path);
479 } break;
480 case kQuadToPath: {
481 SkPoint pt[2];
482 makePointArray(SK_ARRAY_COUNT(pt), pt);
483 path.quadTo(pt[0], pt[1]);
484 validate(path);
485 } break;
486 case kRQuadToPath: {
487 SkPoint pt[2];
488 makePointArray(SK_ARRAY_COUNT(pt), pt);
489 path.rQuadTo(pt[0].fX, pt[0].fY, pt[1].fX, pt[1].fY);
490 validate(path);
491 } break;
492 case kConicToPath: {
493 SkPoint pt[2];
494 makePointArray(SK_ARRAY_COUNT(pt), pt);
495 SkScalar weight = makeScalar();
496 path.conicTo(pt[0], pt[1], weight);
497 validate(path);
498 } break;
499 case kRConicToPath: {
500 SkPoint pt[2];
501 makePointArray(SK_ARRAY_COUNT(pt), pt);
502 SkScalar weight = makeScalar();
503 path.rConicTo(pt[0].fX, pt[0].fY, pt[1].fX, pt[1].fY, weight);
504 validate(path);
505 } break;
506 case kCubicToPath: {
507 SkPoint pt[3];
508 makePointArray(SK_ARRAY_COUNT(pt), pt);
509 path.cubicTo(pt[0], pt[1], pt[2]);
510 validate(path);
511 } break;
512 case kRCubicToPath: {
513 SkPoint pt[3];
514 makePointArray(SK_ARRAY_COUNT(pt), pt);
515 path.rCubicTo(pt[0].fX, pt[0].fY, pt[1].fX, pt[1].fY, pt[2].fX, pt[2].fY);
516 validate(path);
517 } break;
518 case kArcToPath: {
519 SkPoint pt[2];
520 makePointArray(SK_ARRAY_COUNT(pt), pt);
521 SkScalar radius = makeScalar();
522 path.arcTo(pt[0], pt[1], radius);
523 validate(path);
524 } break;
525 case kArcTo2Path: {
526 SkRect oval = makeRect();
527 SkScalar startAngle = makeAngle();
528 SkScalar sweepAngle = makeAngle();
529 bool forceMoveTo = makeBool();
530 path.arcTo(oval, startAngle, sweepAngle, forceMoveTo);
531 validate(path);
532 } break;
533 case kClosePath:
534 path.close();
535 validate(path);
536 break;
537 }
538 }
539 }
540 return path;
541}
542
543uint32_t makeSegmentCount() {
544 return fRand.nextRangeU(1, fPathSegmentLimit);
545}
546
547RandomSetRRect makeSetRRectType() {
548 return (RandomSetRRect) fRand.nextRangeU(0, kRandomSetRRect_Last);
549}
550
551SkScalar makeScalar() {
552 SkScalar scalar;
553 scalar = fRand.nextRangeF(fFloatMin, fFloatMax);
554 return scalar;
555}
556
557void makeScalarArray(size_t arrayCount, SkScalar* array) {
558 for (size_t index = 0; index < arrayCount; ++index) {
559 array[index] = makeScalar();
560 }
561}
562
563void makeVectorArray(size_t arrayCount, SkVector* array) {
564 for (size_t index = 0; index < arrayCount; ++index) {
565 array[index] = makeVector();
566 }
567}
568
569SkVector makeVector() {
570 SkVector result;
571 makeScalarArray(2, &result.fX);
572 return result;
573}
574
575void validate(const SkPath& path) {
576 if (fValidate) {
Cary Clark0461e9f2017-08-25 15:13:38 -0400577 // FIXME: this could probably assert on path.isValid() instead
578 SkDEBUGCODE(path.validateRef());
caryclark63c684a2015-02-25 09:04:04 -0800579 }
580}
581
582SkRandom fRand;
583SkMatrix fMatrix;
584SkPath fClip;
585SkPaint fPaint;
586SkPath fPath;
587SkScalar fFloatMin;
588SkScalar fFloatMax;
589uint32_t fPathContourCount;
590int fPathDepth;
591int fPathDepthLimit;
592uint32_t fPathSegmentLimit;
593int fAddCount;
594bool fPrintName;
caryclark94b4ee82015-03-04 12:32:22 -0800595bool fStrokeOnly;
caryclark63c684a2015-02-25 09:04:04 -0800596bool fValidate;
597const char* fTab;
598};
599
caryclark63c684a2015-02-25 09:04:04 -0800600static bool contains_only_moveTo(const SkPath& path) {
601 int verbCount = path.countVerbs();
602 if (verbCount == 0) {
603 return true;
604 }
605 SkTDArray<uint8_t> verbs;
606 verbs.setCount(verbCount);
607 SkDEBUGCODE(int getVerbResult = ) path.getVerbs(verbs.begin(), verbCount);
608 SkASSERT(getVerbResult == verbCount);
609 for (int index = 0; index < verbCount; ++index) {
610 if (verbs[index] != SkPath::kMove_Verb) {
611 return false;
612 }
613 }
614 return true;
615}
616
caryclark94b4ee82015-03-04 12:32:22 -0800617#include "SkGraphics.h"
618#include "SkSurface.h"
619#include "SkTaskGroup.h"
620#include "SkTDArray.h"
621
caryclark94b4ee82015-03-04 12:32:22 -0800622static void path_fuzz_stroker(SkBitmap* bitmap, int seed) {
mtklein279c7862016-01-04 19:13:19 -0800623 SkTaskGroup().batch(100, [&](int i) {
mtklein00b621c2015-06-17 15:26:15 -0700624 int localSeed = seed + i;
625
626 FuzzPath fuzzPath;
627 fuzzPath.setStrokeOnly();
628 fuzzPath.setSeed(localSeed);
629 fuzzPath.randomize();
630 const SkPath& path = fuzzPath.getPath();
631 const SkPaint& paint = fuzzPath.getPaint();
632 const SkImageInfo& info = bitmap->info();
Mike Reed5df49342016-11-12 08:06:55 -0600633 std::unique_ptr<SkCanvas> canvas(
634 SkCanvas::MakeRasterDirect(info, bitmap->getPixels(), bitmap->rowBytes()));
mtklein00b621c2015-06-17 15:26:15 -0700635 int w = info.width() / 4;
636 int h = info.height() / 4;
637 int x = localSeed / 4 % 4;
638 int y = localSeed % 4;
639 SkRect clipBounds = SkRect::MakeXYWH(SkIntToScalar(x) * w, SkIntToScalar(y) * h,
640 SkIntToScalar(w), SkIntToScalar(h));
641 canvas->save();
642 canvas->clipRect(clipBounds);
643 canvas->translate(SkIntToScalar(x) * w, SkIntToScalar(y) * h);
644 canvas->drawPath(path, paint);
645 canvas->restore();
646 });
caryclark94b4ee82015-03-04 12:32:22 -0800647}
648
caryclark63c684a2015-02-25 09:04:04 -0800649class PathFuzzView : public SampleView {
650public:
caryclark94b4ee82015-03-04 12:32:22 -0800651 PathFuzzView()
652 : fOneDraw(false)
653 {
caryclark63c684a2015-02-25 09:04:04 -0800654 }
655protected:
656 // overrides from SkEventSink
mtkleinf0599002015-07-13 06:18:39 -0700657 bool onQuery(SkEvent* evt) override {
caryclark63c684a2015-02-25 09:04:04 -0800658 if (SampleCode::TitleQ(*evt)) {
659 SampleCode::TitleR(evt, "PathFuzzer");
660 return true;
661 }
662 return this->INHERITED::onQuery(evt);
663 }
664
mtklein36352bf2015-03-25 18:17:31 -0700665 void onOnceBeforeDraw() override {
caryclark94b4ee82015-03-04 12:32:22 -0800666 fIndex = 0;
mtklein00b621c2015-06-17 15:26:15 -0700667 SkImageInfo info(SkImageInfo::MakeN32Premul(SkScalarRoundToInt(width()),
caryclark94b4ee82015-03-04 12:32:22 -0800668 SkScalarRoundToInt(height())));
669 offscreen.allocPixels(info);
670 path_fuzz_stroker(&offscreen, fIndex);
671 }
672
mtkleinf0599002015-07-13 06:18:39 -0700673 void onDrawContent(SkCanvas* canvas) override {
caryclark94b4ee82015-03-04 12:32:22 -0800674 if (fOneDraw) {
675 fuzzPath.randomize();
676 const SkPath& path = fuzzPath.getPath();
677 const SkPaint& paint = fuzzPath.getPaint();
678 const SkPath& clip = fuzzPath.getClip();
679 const SkMatrix& matrix = fuzzPath.getMatrix();
680 if (!contains_only_moveTo(clip)) {
681 canvas->clipPath(clip);
682 }
683 canvas->setMatrix(matrix);
684 canvas->drawPath(path, paint);
685 } else {
686 path_fuzz_stroker(&offscreen, fIndex += 100);
687 canvas->drawBitmap(offscreen, 0, 0);
caryclark63c684a2015-02-25 09:04:04 -0800688 }
halcanary96fcdcc2015-08-27 07:41:13 -0700689 this->inval(nullptr);
caryclark63c684a2015-02-25 09:04:04 -0800690 }
691
692private:
caryclark94b4ee82015-03-04 12:32:22 -0800693 int fIndex;
694 SkBitmap offscreen;
caryclark63c684a2015-02-25 09:04:04 -0800695 FuzzPath fuzzPath;
caryclark94b4ee82015-03-04 12:32:22 -0800696 bool fOneDraw;
caryclark63c684a2015-02-25 09:04:04 -0800697 typedef SkView INHERITED;
698};
699
caryclark63c684a2015-02-25 09:04:04 -0800700static SkView* MyFactory() { return new PathFuzzView; }
701static SkViewRegister reg(MyFactory);