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