blob: 35951d77cc2766c69ac8aca4ac97223518098f40 [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
Ben Wagnerb2c4ea62018-08-08 11:36:17 -04008#include "Sample.h"
caryclark63c684a2015-02-25 09:04:04 -08009#include "SkCanvas.h"
10#include "SkPaint.h"
11#include "SkPath.h"
12#include "SkMatrix.h"
13#include "SkColor.h"
14#include "SkTDArray.h"
15#include "SkRandom.h"
bungemand3ebb482015-08-05 13:57:49 -070016#include "SkRRect.h"
caryclark63c684a2015-02-25 09:04:04 -080017
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) {
Cary Clark0461e9f2017-08-25 15:13:38 -0400576 // FIXME: this could probably assert on path.isValid() instead
577 SkDEBUGCODE(path.validateRef());
caryclark63c684a2015-02-25 09:04:04 -0800578 }
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
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400648class PathFuzzView : public Sample {
caryclark63c684a2015-02-25 09:04:04 -0800649public:
caryclark94b4ee82015-03-04 12:32:22 -0800650 PathFuzzView()
651 : fOneDraw(false)
652 {
caryclark63c684a2015-02-25 09:04:04 -0800653 }
654protected:
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400655 bool onQuery(Sample::Event* evt) override {
656 if (Sample::TitleQ(*evt)) {
657 Sample::TitleR(evt, "PathFuzzer");
caryclark63c684a2015-02-25 09:04:04 -0800658 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
mtkleinf0599002015-07-13 06:18:39 -0700671 void onDrawContent(SkCanvas* canvas) override {
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 }
688
689private:
caryclark94b4ee82015-03-04 12:32:22 -0800690 int fIndex;
691 SkBitmap offscreen;
caryclark63c684a2015-02-25 09:04:04 -0800692 FuzzPath fuzzPath;
caryclark94b4ee82015-03-04 12:32:22 -0800693 bool fOneDraw;
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400694 typedef Sample INHERITED;
caryclark63c684a2015-02-25 09:04:04 -0800695};
696
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400697DEF_SAMPLE( return new PathFuzzView(); )