blob: b66b88154745cd2f6da53949aff97bc0044f2396 [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) {
577 SkDEBUGCODE(path.experimentalValidateRef());
578 }
579}
580
581SkRandom fRand;
582SkMatrix fMatrix;
583SkPath fClip;
584SkPaint fPaint;
585SkPath fPath;
586SkScalar fFloatMin;
587SkScalar fFloatMax;
588uint32_t fPathContourCount;
589int fPathDepth;
590int fPathDepthLimit;
591uint32_t fPathSegmentLimit;
592int fAddCount;
593bool fPrintName;
caryclark94b4ee82015-03-04 12:32:22 -0800594bool fStrokeOnly;
caryclark63c684a2015-02-25 09:04:04 -0800595bool fValidate;
596const char* fTab;
597};
598
caryclark63c684a2015-02-25 09:04:04 -0800599static bool contains_only_moveTo(const SkPath& path) {
600 int verbCount = path.countVerbs();
601 if (verbCount == 0) {
602 return true;
603 }
604 SkTDArray<uint8_t> verbs;
605 verbs.setCount(verbCount);
606 SkDEBUGCODE(int getVerbResult = ) path.getVerbs(verbs.begin(), verbCount);
607 SkASSERT(getVerbResult == verbCount);
608 for (int index = 0; index < verbCount; ++index) {
609 if (verbs[index] != SkPath::kMove_Verb) {
610 return false;
611 }
612 }
613 return true;
614}
615
caryclark94b4ee82015-03-04 12:32:22 -0800616#include "SkGraphics.h"
617#include "SkSurface.h"
618#include "SkTaskGroup.h"
619#include "SkTDArray.h"
620
caryclark94b4ee82015-03-04 12:32:22 -0800621static void path_fuzz_stroker(SkBitmap* bitmap, int seed) {
mtklein279c7862016-01-04 19:13:19 -0800622 SkTaskGroup().batch(100, [&](int i) {
mtklein00b621c2015-06-17 15:26:15 -0700623 int localSeed = seed + i;
624
625 FuzzPath fuzzPath;
626 fuzzPath.setStrokeOnly();
627 fuzzPath.setSeed(localSeed);
628 fuzzPath.randomize();
629 const SkPath& path = fuzzPath.getPath();
630 const SkPaint& paint = fuzzPath.getPaint();
631 const SkImageInfo& info = bitmap->info();
Mike Reed5df49342016-11-12 08:06:55 -0600632 std::unique_ptr<SkCanvas> canvas(
633 SkCanvas::MakeRasterDirect(info, bitmap->getPixels(), bitmap->rowBytes()));
mtklein00b621c2015-06-17 15:26:15 -0700634 int w = info.width() / 4;
635 int h = info.height() / 4;
636 int x = localSeed / 4 % 4;
637 int y = localSeed % 4;
638 SkRect clipBounds = SkRect::MakeXYWH(SkIntToScalar(x) * w, SkIntToScalar(y) * h,
639 SkIntToScalar(w), SkIntToScalar(h));
640 canvas->save();
641 canvas->clipRect(clipBounds);
642 canvas->translate(SkIntToScalar(x) * w, SkIntToScalar(y) * h);
643 canvas->drawPath(path, paint);
644 canvas->restore();
645 });
caryclark94b4ee82015-03-04 12:32:22 -0800646}
647
caryclark63c684a2015-02-25 09:04:04 -0800648class PathFuzzView : public SampleView {
649public:
caryclark94b4ee82015-03-04 12:32:22 -0800650 PathFuzzView()
651 : fOneDraw(false)
652 {
caryclark63c684a2015-02-25 09:04:04 -0800653 }
654protected:
655 // overrides from SkEventSink
mtkleinf0599002015-07-13 06:18:39 -0700656 bool onQuery(SkEvent* evt) override {
caryclark63c684a2015-02-25 09:04:04 -0800657 if (SampleCode::TitleQ(*evt)) {
658 SampleCode::TitleR(evt, "PathFuzzer");
659 return true;
660 }
661 return this->INHERITED::onQuery(evt);
662 }
663
mtklein36352bf2015-03-25 18:17:31 -0700664 void onOnceBeforeDraw() override {
caryclark94b4ee82015-03-04 12:32:22 -0800665 fIndex = 0;
mtklein00b621c2015-06-17 15:26:15 -0700666 SkImageInfo info(SkImageInfo::MakeN32Premul(SkScalarRoundToInt(width()),
caryclark94b4ee82015-03-04 12:32:22 -0800667 SkScalarRoundToInt(height())));
668 offscreen.allocPixels(info);
669 path_fuzz_stroker(&offscreen, fIndex);
670 }
671
mtkleinf0599002015-07-13 06:18:39 -0700672 void onDrawContent(SkCanvas* canvas) override {
caryclark94b4ee82015-03-04 12:32:22 -0800673 if (fOneDraw) {
674 fuzzPath.randomize();
675 const SkPath& path = fuzzPath.getPath();
676 const SkPaint& paint = fuzzPath.getPaint();
677 const SkPath& clip = fuzzPath.getClip();
678 const SkMatrix& matrix = fuzzPath.getMatrix();
679 if (!contains_only_moveTo(clip)) {
680 canvas->clipPath(clip);
681 }
682 canvas->setMatrix(matrix);
683 canvas->drawPath(path, paint);
684 } else {
685 path_fuzz_stroker(&offscreen, fIndex += 100);
686 canvas->drawBitmap(offscreen, 0, 0);
caryclark63c684a2015-02-25 09:04:04 -0800687 }
halcanary96fcdcc2015-08-27 07:41:13 -0700688 this->inval(nullptr);
caryclark63c684a2015-02-25 09:04:04 -0800689 }
690
691private:
caryclark94b4ee82015-03-04 12:32:22 -0800692 int fIndex;
693 SkBitmap offscreen;
caryclark63c684a2015-02-25 09:04:04 -0800694 FuzzPath fuzzPath;
caryclark94b4ee82015-03-04 12:32:22 -0800695 bool fOneDraw;
caryclark63c684a2015-02-25 09:04:04 -0800696 typedef SkView INHERITED;
697};
698
caryclark63c684a2015-02-25 09:04:04 -0800699static SkView* MyFactory() { return new PathFuzzView; }
700static SkViewRegister reg(MyFactory);