2 * Copyright 2015 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "SampleCode.h"
15 #include "SkTDArray.h"
43 const int kRandomAddPath_Last = kReverseAddPath;
45 const char* gRandomAddPathNames[] = {
79 const char* gRandomSetRRectNames[] = {
88 int kRandomSetRRect_Last = kSetRectRadii;
90 enum RandomSetMatrix {
110 int kRandomSetMatrix_Last = kSetAll;
112 const char* gRandomSetMatrixNames[] = {
118 "kSetScaleTranslate",
126 "kSetRotateTranslate",
146 fPathDepthLimit = fRand.nextRangeU(1, 2);
147 fPathContourCount = fRand.nextRangeU(1, 4);
148 fPathSegmentLimit = fRand.nextRangeU(1, 8);
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);
157 SkASSERT(!fPathDepth);
160 const SkPath& getClip() const {
164 const SkMatrix& getMatrix() const {
168 const SkPaint& getPaint() const {
172 const SkPath& getPath() const {
176 void setSeed(int seed) {
180 void setStrokeOnly() {
186 SkPath::AddPathMode makeAddPathMode() {
187 return (SkPath::AddPathMode) fRand.nextRangeU(SkPath::kAppend_AddPathMode,
188 SkPath::kExtend_AddPathMode);
191 RandomAddPath makeAddPathType() {
192 return (RandomAddPath) fRand.nextRangeU(0, kRandomAddPath_Last);
195 SkScalar makeAngle() {
197 angle = fRand.nextF();
202 return fRand.nextBool();
205 SkPath::Direction makeDirection() {
206 return (SkPath::Direction) fRand.nextRangeU(SkPath::kCW_Direction, SkPath::kCCW_Direction);
209 SkMatrix makeMatrix() {
212 RandomSetMatrix setMatrix = (RandomSetMatrix) fRand.nextRangeU(0, kRandomSetMatrix_Last);
214 SkDebugf("%.*s%s\n", fPathDepth * 3, fTab, gRandomSetMatrixNames[setMatrix]);
220 matrix.setTranslateX(makeScalar());
223 matrix.setTranslateY(makeScalar());
226 matrix.setTranslate(makeScalar(), makeScalar());
229 matrix.setScaleX(makeScalar());
232 matrix.setScaleY(makeScalar());
235 matrix.setScale(makeScalar(), makeScalar());
237 case kSetScaleTranslate:
238 matrix.setScale(makeScalar(), makeScalar(), makeScalar(), makeScalar());
241 matrix.setSkewX(makeScalar());
244 matrix.setSkewY(makeScalar());
247 matrix.setSkew(makeScalar(), makeScalar());
249 case kSetSkewTranslate:
250 matrix.setSkew(makeScalar(), makeScalar(), makeScalar(), makeScalar());
253 matrix.setRotate(makeScalar());
255 case kSetRotateTranslate:
256 matrix.setRotate(makeScalar(), makeScalar(), makeScalar());
258 case kSetPerspectiveX:
259 matrix.setPerspX(makeScalar());
261 case kSetPerspectiveY:
262 matrix.setPerspY(makeScalar());
265 matrix.setAll(makeScalar(), makeScalar(), makeScalar(),
266 makeScalar(), makeScalar(), makeScalar(),
267 makeScalar(), makeScalar(), makeScalar());
273 SkPaint makePaint() {
275 bool antiAlias = fRand.nextBool();
276 paint.setAntiAlias(antiAlias);
277 SkPaint::Style style = fStrokeOnly ? SkPaint::kStroke_Style :
278 (SkPaint::Style) fRand.nextRangeU(SkPaint::kFill_Style, SkPaint::kStrokeAndFill_Style);
279 paint.setStyle(style);
280 SkColor color = (SkColor) fRand.nextU();
281 paint.setColor(color);
282 SkScalar width = fRand.nextRangeF(0, 10);
283 paint.setStrokeWidth(width);
284 SkScalar miter = makeScalar();
285 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);
294 SkPoint makePoint() {
296 makeScalarArray(2, &result.fX);
300 void makePointArray(size_t arrayCount, SkPoint* points) {
301 for (size_t index = 0; index < arrayCount; ++index) {
302 points[index] = makePoint();
306 void 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();
315 makeScalarArray(4, &result.fLeft);
319 SkRRect makeRRect() {
321 RandomSetRRect rrectType = makeSetRRectType();
323 SkDebugf("%.*s%s\n", fPathDepth * 3, fTab, gRandomSetRRectNames[rrectType]);
330 SkRect rect = makeRect();
334 SkRect oval = makeRect();
338 SkRect rect = makeRect();
339 SkScalar xRad = makeScalar();
340 SkScalar yRad = makeScalar();
341 rrect.setRectXY(rect, xRad, yRad);
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
352 case kSetRectRadii: {
353 SkRect rect = makeRect();
355 makeVectorArray(SK_ARRAY_COUNT(radii), radii);
356 rrect.setRectRadii(rect, radii);
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();
370 SkDebugf("%.*s%s\n", fPathDepth * 3, fTab,
371 gRandomAddPathNames[addPathType]);
373 switch (addPathType) {
375 SkRect oval = makeRect();
376 SkScalar startAngle = makeAngle();
377 SkScalar sweepAngle = makeAngle();
378 path.addArc(oval, startAngle, sweepAngle);
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);
388 case kAddRoundRect2: {
389 SkRect rect = makeRect();
391 makeScalarArray(SK_ARRAY_COUNT(radii), radii);
392 SkPath::Direction dir = makeDirection();
393 path.addRoundRect(rect, radii, dir);
397 SkRRect rrect = makeRRect();
398 SkPath::Direction dir = makeDirection();
399 path.addRRect(rrect, dir);
403 SkTDArray<SkPoint> points;
404 makePointArray(&points);
405 bool close = makeBool();
406 path.addPoly(&points[0], points.count(), close);
410 if (fPathDepth < fPathDepthLimit) {
412 SkPath src = makePath();
414 SkScalar dx = makeScalar();
415 SkScalar dy = makeScalar();
416 SkPath::AddPathMode mode = makeAddPathMode();
417 path.addPath(src, dx, dy, mode);
423 if (fPathDepth < fPathDepthLimit) {
425 SkPath src = makePath();
427 SkPath::AddPathMode mode = makeAddPathMode();
428 path.addPath(src, mode);
434 if (fPathDepth < fPathDepthLimit) {
436 SkPath src = makePath();
438 SkMatrix matrix = makeMatrix();
439 SkPath::AddPathMode mode = makeAddPathMode();
440 path.addPath(src, matrix, mode);
445 case kReverseAddPath:
446 if (fPathDepth < fPathDepthLimit) {
448 SkPath src = makePath();
450 path.reverseAddPath(src);
456 SkScalar x = makeScalar();
457 SkScalar y = makeScalar();
462 SkScalar x = makeScalar();
463 SkScalar y = makeScalar();
468 SkScalar x = makeScalar();
469 SkScalar y = makeScalar();
474 SkScalar x = makeScalar();
475 SkScalar y = makeScalar();
481 makePointArray(SK_ARRAY_COUNT(pt), pt);
482 path.quadTo(pt[0], pt[1]);
487 makePointArray(SK_ARRAY_COUNT(pt), pt);
488 path.rQuadTo(pt[0].fX, pt[0].fY, pt[1].fX, pt[1].fY);
493 makePointArray(SK_ARRAY_COUNT(pt), pt);
494 SkScalar weight = makeScalar();
495 path.conicTo(pt[0], pt[1], weight);
498 case kRConicToPath: {
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);
507 makePointArray(SK_ARRAY_COUNT(pt), pt);
508 path.cubicTo(pt[0], pt[1], pt[2]);
511 case kRCubicToPath: {
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);
519 makePointArray(SK_ARRAY_COUNT(pt), pt);
520 SkScalar radius = makeScalar();
521 path.arcTo(pt[0], pt[1], radius);
525 SkRect oval = makeRect();
526 SkScalar startAngle = makeAngle();
527 SkScalar sweepAngle = makeAngle();
528 bool forceMoveTo = makeBool();
529 path.arcTo(oval, startAngle, sweepAngle, forceMoveTo);
542 uint32_t makeSegmentCount() {
543 return fRand.nextRangeU(1, fPathSegmentLimit);
546 RandomSetRRect makeSetRRectType() {
547 return (RandomSetRRect) fRand.nextRangeU(0, kRandomSetRRect_Last);
550 SkScalar makeScalar() {
552 scalar = fRand.nextRangeF(fFloatMin, fFloatMax);
556 void makeScalarArray(size_t arrayCount, SkScalar* array) {
557 for (size_t index = 0; index < arrayCount; ++index) {
558 array[index] = makeScalar();
562 void makeVectorArray(size_t arrayCount, SkVector* array) {
563 for (size_t index = 0; index < arrayCount; ++index) {
564 array[index] = makeVector();
568 SkVector makeVector() {
570 makeScalarArray(2, &result.fX);
574 void validate(const SkPath& path) {
576 SkDEBUGCODE(path.experimentalValidateRef());
587 uint32_t fPathContourCount;
590 uint32_t fPathSegmentLimit;
598 static bool contains_only_moveTo(const SkPath& path) {
599 int verbCount = path.countVerbs();
600 if (verbCount == 0) {
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) {
615 #include "SkGraphics.h"
616 #include "SkSurface.h"
617 #include "SkTaskGroup.h"
618 #include "SkTDArray.h"
622 const SkBitmap* fBitmap;
625 static void test_fuzz(ThreadState* data) {
627 fuzzPath.setStrokeOnly();
628 fuzzPath.setSeed(data->fSeed);
629 fuzzPath.randomize();
630 const SkPath& path = fuzzPath.getPath();
631 const SkPaint& paint = fuzzPath.getPaint();
632 const SkImageInfo& info = data->fBitmap->info();
633 SkCanvas* canvas(SkCanvas::NewRasterDirect(info, data->fBitmap->getPixels(),
634 data->fBitmap->rowBytes()));
635 int w = info.width() / 4;
636 int h = info.height() / 4;
637 int x = data->fSeed / 4 % 4;
638 int y = data->fSeed % 4;
639 SkRect clipBounds = SkRect::MakeXYWH(SkIntToScalar(x) * w, SkIntToScalar(y) * h,
640 SkIntToScalar(w), SkIntToScalar(h));
642 canvas->clipRect(clipBounds);
643 canvas->translate(SkIntToScalar(x) * w, SkIntToScalar(y) * h);
644 canvas->drawPath(path, paint);
648 static void path_fuzz_stroker(SkBitmap* bitmap, int seed) {
649 ThreadState states[100];
650 for (size_t i = 0; i < SK_ARRAY_COUNT(states); i++) {
651 states[i].fSeed = seed + (int) i;
652 states[i].fBitmap = bitmap;
655 tg.batch(test_fuzz, states, SK_ARRAY_COUNT(states));
658 class PathFuzzView : public SampleView {
665 // overrides from SkEventSink
666 virtual bool onQuery(SkEvent* evt) {
667 if (SampleCode::TitleQ(*evt)) {
668 SampleCode::TitleR(evt, "PathFuzzer");
671 return this->INHERITED::onQuery(evt);
674 void onOnceBeforeDraw() override {
676 SkImageInfo info(SkImageInfo::MakeN32Premul(SkScalarRoundToInt(width()),
677 SkScalarRoundToInt(height())));
678 offscreen.allocPixels(info);
679 path_fuzz_stroker(&offscreen, fIndex);
682 virtual void onDrawContent(SkCanvas* canvas) {
684 fuzzPath.randomize();
685 const SkPath& path = fuzzPath.getPath();
686 const SkPaint& paint = fuzzPath.getPaint();
687 const SkPath& clip = fuzzPath.getClip();
688 const SkMatrix& matrix = fuzzPath.getMatrix();
689 if (!contains_only_moveTo(clip)) {
690 canvas->clipPath(clip);
692 canvas->setMatrix(matrix);
693 canvas->drawPath(path, paint);
695 path_fuzz_stroker(&offscreen, fIndex += 100);
696 canvas->drawBitmap(offscreen, 0, 0);
706 typedef SkView INHERITED;
709 static SkView* MyFactory() { return new PathFuzzView; }
710 static SkViewRegister reg(MyFactory);