diff options
Diffstat (limited to 'samplecode/SamplePathFuzz.cpp')
| -rw-r--r-- | samplecode/SamplePathFuzz.cpp | 651 |
1 files changed, 651 insertions, 0 deletions
diff --git a/samplecode/SamplePathFuzz.cpp b/samplecode/SamplePathFuzz.cpp new file mode 100644 index 0000000000..d6b11c5971 --- /dev/null +++ b/samplecode/SamplePathFuzz.cpp @@ -0,0 +1,651 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SampleCode.h" +#include "SkView.h" +#include "SkCanvas.h" +#include "SkPaint.h" +#include "SkPath.h" +#include "SkMatrix.h" +#include "SkColor.h" +#include "SkTDArray.h" +#include "SkRandom.h" + +enum RandomAddPath { + kMoveToPath, + kRMoveToPath, + kLineToPath, + kRLineToPath, + kQuadToPath, + kRQuadToPath, + kConicToPath, + kRConicToPath, + kCubicToPath, + kRCubicToPath, + kArcToPath, + kArcTo2Path, + kClosePath, + kAddArc, + kAddRoundRect1, + kAddRoundRect2, + kAddRRect, + kAddPoly, + kAddPath1, + kAddPath2, + kAddPath3, + kReverseAddPath, +}; + +const int kRandomAddPath_Last = kReverseAddPath; + +const char* gRandomAddPathNames[] = { + "kMoveToPath", + "kRMoveToPath", + "kLineToPath", + "kRLineToPath", + "kQuadToPath", + "kRQuadToPath", + "kConicToPath", + "kRConicToPath", + "kCubicToPath", + "kRCubicToPath", + "kArcToPath", + "kArcTo2Path", + "kClosePath", + "kAddArc", + "kAddRoundRect1", + "kAddRoundRect2", + "kAddRRect", + "kAddPoly", + "kAddPath1", + "kAddPath2", + "kAddPath3", + "kReverseAddPath", +}; + +enum RandomSetRRect { + kSetEmpty, + kSetRect, + kSetOval, + kSetRectXY, + kSetNinePatch, + kSetRectRadii, +}; + +const char* gRandomSetRRectNames[] = { + "kSetEmpty", + "kSetRect", + "kSetOval", + "kSetRectXY", + "kSetNinePatch", + "kSetRectRadii", +}; + +int kRandomSetRRect_Last = kSetRectRadii; + +enum RandomSetMatrix { + kSetIdentity, + kSetTranslate, + kSetTranslateX, + kSetTranslateY, + kSetScale, + kSetScaleTranslate, + kSetScaleX, + kSetScaleY, + kSetSkew, + kSetSkewTranslate, + kSetSkewX, + kSetSkewY, + kSetRotate, + kSetRotateTranslate, + kSetPerspectiveX, + kSetPerspectiveY, + kSetAll, +}; + +int kRandomSetMatrix_Last = kSetAll; + +const char* gRandomSetMatrixNames[] = { + "kSetIdentity", + "kSetTranslate", + "kSetTranslateX", + "kSetTranslateY", + "kSetScale", + "kSetScaleTranslate", + "kSetScaleX", + "kSetScaleY", + "kSetSkew", + "kSetSkewTranslate", + "kSetSkewX", + "kSetSkewY", + "kSetRotate", + "kSetRotateTranslate", + "kSetPerspectiveX", + "kSetPerspectiveY", + "kSetAll", +}; + +class FuzzPath { +public: + FuzzPath() + : fFloatMin(0) + , fFloatMax(800) + , fAddCount(0) + , fPrintName(false) + , fValidate(false) + { + fTab = " "; + } + void randomize() { + fPathDepth = 0; + fPathDepthLimit = fRand.nextRangeU(1, 2); + fPathContourCount = fRand.nextRangeU(1, 4); + fPathSegmentLimit = fRand.nextRangeU(1, 8); + fClip = makePath(); + SkASSERT(!fPathDepth); + fMatrix = makeMatrix(); + fPaint = makePaint(); + fPathDepthLimit = fRand.nextRangeU(1, 3); + fPathContourCount = fRand.nextRangeU(1, 6); + fPathSegmentLimit = fRand.nextRangeU(1, 16); + fPath = makePath(); + SkASSERT(!fPathDepth); + } + + const SkPath& getClip() const { + return fClip; + } + + const SkMatrix& getMatrix() const { + return fMatrix; + } + + const SkPaint& getPaint() const { + return fPaint; + } + + const SkPath& getPath() const { + return fPath; + } + +private: + +SkPath::AddPathMode makeAddPathMode() { + return (SkPath::AddPathMode) fRand.nextRangeU(SkPath::kAppend_AddPathMode, + SkPath::kExtend_AddPathMode); +} + +RandomAddPath makeAddPathType() { + return (RandomAddPath) fRand.nextRangeU(0, kRandomAddPath_Last); +} + +SkScalar makeAngle() { + SkScalar angle; + angle = fRand.nextF(); + return angle; +} + +bool makeBool() { + return fRand.nextBool(); +} + +SkPath::Direction makeDirection() { + return (SkPath::Direction) fRand.nextRangeU(SkPath::kCW_Direction, SkPath::kCCW_Direction); +} + +SkMatrix makeMatrix() { + SkMatrix matrix; + matrix.reset(); + RandomSetMatrix setMatrix = (RandomSetMatrix) fRand.nextRangeU(0, kRandomSetMatrix_Last); + if (fPrintName) { + SkDebugf("%.*s%s\n", fPathDepth * 3, fTab, gRandomSetMatrixNames[setMatrix]); + } + switch (setMatrix) { + case kSetIdentity: + break; + case kSetTranslateX: + matrix.setTranslateX(makeScalar()); + break; + case kSetTranslateY: + matrix.setTranslateY(makeScalar()); + break; + case kSetTranslate: + matrix.setTranslate(makeScalar(), makeScalar()); + break; + case kSetScaleX: + matrix.setScaleX(makeScalar()); + break; + case kSetScaleY: + matrix.setScaleY(makeScalar()); + break; + case kSetScale: + matrix.setScale(makeScalar(), makeScalar()); + break; + case kSetScaleTranslate: + matrix.setScale(makeScalar(), makeScalar(), makeScalar(), makeScalar()); + break; + case kSetSkewX: + matrix.setSkewX(makeScalar()); + break; + case kSetSkewY: + matrix.setSkewY(makeScalar()); + break; + case kSetSkew: + matrix.setSkew(makeScalar(), makeScalar()); + break; + case kSetSkewTranslate: + matrix.setSkew(makeScalar(), makeScalar(), makeScalar(), makeScalar()); + break; + case kSetRotate: + matrix.setRotate(makeScalar()); + break; + case kSetRotateTranslate: + matrix.setRotate(makeScalar(), makeScalar(), makeScalar()); + break; + case kSetPerspectiveX: + matrix.setPerspX(makeScalar()); + break; + case kSetPerspectiveY: + matrix.setPerspY(makeScalar()); + break; + case kSetAll: + matrix.setAll(makeScalar(), makeScalar(), makeScalar(), + makeScalar(), makeScalar(), makeScalar(), + makeScalar(), makeScalar(), makeScalar()); + break; + } + return matrix; +} + +SkPaint makePaint() { + SkPaint paint; + bool antiAlias = fRand.nextBool(); + paint.setAntiAlias(antiAlias); + SkPaint::Style style = (SkPaint::Style) fRand.nextRangeU(SkPaint::kFill_Style, + SkPaint::kStrokeAndFill_Style); + paint.setStyle(style); + SkColor color = (SkColor) fRand.nextU(); + paint.setColor(color); + SkScalar width = fRand.nextF(); + paint.setStrokeWidth(width); + SkScalar miter = fRand.nextF(); + paint.setStrokeMiter(miter); + SkPaint::Cap cap = (SkPaint::Cap) fRand.nextRangeU(SkPaint::kButt_Cap, SkPaint::kSquare_Cap); + paint.setStrokeCap(cap); + SkPaint::Join join = (SkPaint::Join) fRand.nextRangeU(SkPaint::kMiter_Join, + SkPaint::kBevel_Join); + paint.setStrokeJoin(join); + return paint; +} + +SkPoint makePoint() { + SkPoint result; + makeScalarArray(2, &result.fX); + return result; +} + +void makePointArray(size_t arrayCount, SkPoint* points) { + for (size_t index = 0; index < arrayCount; ++index) { + points[index] = makePoint(); + } +} + +void makePointArray(SkTDArray<SkPoint>* points) { + size_t arrayCount = fRand.nextRangeU(1, 10); + for (size_t index = 0; index < arrayCount; ++index) { + *points->append() = makePoint(); + } +} + +SkRect makeRect() { + SkRect result; + makeScalarArray(4, &result.fLeft); + return result; +} + +SkRRect makeRRect() { + SkRRect rrect; + RandomSetRRect rrectType = makeSetRRectType(); + if (fPrintName) { + SkDebugf("%.*s%s\n", fPathDepth * 3, fTab, gRandomSetRRectNames[rrectType]); + } + switch (rrectType) { + case kSetEmpty: + rrect.setEmpty(); + break; + case kSetRect: { + SkRect rect = makeRect(); + rrect.setRect(rect); + } break; + case kSetOval: { + SkRect oval = makeRect(); + rrect.setOval(oval); + } break; + case kSetRectXY: { + SkRect rect = makeRect(); + SkScalar xRad = makeScalar(); + SkScalar yRad = makeScalar(); + rrect.setRectXY(rect, xRad, yRad); + } break; + case kSetNinePatch: { + SkRect rect = makeRect(); + SkScalar leftRad = makeScalar(); + SkScalar topRad = makeScalar(); + SkScalar rightRad = makeScalar(); + SkScalar bottomRad = makeScalar(); + rrect.setNinePatch(rect, leftRad, topRad, rightRad, bottomRad); + SkDebugf(""); // keep locals in scope + } break; + case kSetRectRadii: { + SkRect rect = makeRect(); + SkVector radii[4]; + makeVectorArray(SK_ARRAY_COUNT(radii), radii); + rrect.setRectRadii(rect, radii); + } break; + } + return rrect; +} + +SkPath makePath() { + SkPath path; + for (uint32_t cIndex = 0; cIndex < fPathContourCount; ++cIndex) { + uint32_t segments = makeSegmentCount(); + for (uint32_t sIndex = 0; sIndex < segments; ++sIndex) { + RandomAddPath addPathType = makeAddPathType(); + ++fAddCount; + if (fPrintName) { + SkDebugf("%.*s%s\n", fPathDepth * 3, fTab, + gRandomAddPathNames[addPathType]); + } + switch (addPathType) { + case kAddArc: { + SkRect oval = makeRect(); + SkScalar startAngle = makeAngle(); + SkScalar sweepAngle = makeAngle(); + path.addArc(oval, startAngle, sweepAngle); + validate(path); + } break; + case kAddRoundRect1: { + SkRect rect = makeRect(); + SkScalar rx = makeScalar(), ry = makeScalar(); + SkPath::Direction dir = makeDirection(); + path.addRoundRect(rect, rx, ry, dir); + validate(path); + } break; + case kAddRoundRect2: { + SkRect rect = makeRect(); + SkScalar radii[8]; + makeScalarArray(SK_ARRAY_COUNT(radii), radii); + SkPath::Direction dir = makeDirection(); + path.addRoundRect(rect, radii, dir); + validate(path); + } break; + case kAddRRect: { + SkRRect rrect = makeRRect(); + SkPath::Direction dir = makeDirection(); + path.addRRect(rrect, dir); + validate(path); + } break; + case kAddPoly: { + SkTDArray<SkPoint> points; + makePointArray(&points); + bool close = makeBool(); + path.addPoly(&points[0], points.count(), close); + validate(path); + } break; + case kAddPath1: + if (fPathDepth < fPathDepthLimit) { + ++fPathDepth; + SkPath src = makePath(); + validate(src); + SkScalar dx = makeScalar(); + SkScalar dy = makeScalar(); + SkPath::AddPathMode mode = makeAddPathMode(); + path.addPath(src, dx, dy, mode); + --fPathDepth; + validate(path); + } + break; + case kAddPath2: + if (fPathDepth < fPathDepthLimit) { + ++fPathDepth; + SkPath src = makePath(); + validate(src); + SkPath::AddPathMode mode = makeAddPathMode(); + path.addPath(src, mode); + --fPathDepth; + validate(path); + } + break; + case kAddPath3: + if (fPathDepth < fPathDepthLimit) { + ++fPathDepth; + SkPath src = makePath(); + validate(src); + SkMatrix matrix = makeMatrix(); + SkPath::AddPathMode mode = makeAddPathMode(); + path.addPath(src, matrix, mode); + --fPathDepth; + validate(path); + } + break; + case kReverseAddPath: + if (fPathDepth < fPathDepthLimit) { + ++fPathDepth; + SkPath src = makePath(); + validate(src); + path.reverseAddPath(src); + --fPathDepth; + validate(path); + } + break; + case kMoveToPath: { + SkScalar x = makeScalar(); + SkScalar y = makeScalar(); + path.moveTo(x, y); + validate(path); + } break; + case kRMoveToPath: { + SkScalar x = makeScalar(); + SkScalar y = makeScalar(); + path.rMoveTo(x, y); + validate(path); + } break; + case kLineToPath: { + SkScalar x = makeScalar(); + SkScalar y = makeScalar(); + path.lineTo(x, y); + validate(path); + } break; + case kRLineToPath: { + SkScalar x = makeScalar(); + SkScalar y = makeScalar(); + path.rLineTo(x, y); + validate(path); + } break; + case kQuadToPath: { + SkPoint pt[2]; + makePointArray(SK_ARRAY_COUNT(pt), pt); + path.quadTo(pt[0], pt[1]); + validate(path); + } break; + case kRQuadToPath: { + SkPoint pt[2]; + makePointArray(SK_ARRAY_COUNT(pt), pt); + path.rQuadTo(pt[0].fX, pt[0].fY, pt[1].fX, pt[1].fY); + validate(path); + } break; + case kConicToPath: { + SkPoint pt[2]; + makePointArray(SK_ARRAY_COUNT(pt), pt); + SkScalar weight = makeScalar(); + path.conicTo(pt[0], pt[1], weight); + validate(path); + } break; + case kRConicToPath: { + SkPoint pt[2]; + makePointArray(SK_ARRAY_COUNT(pt), pt); + SkScalar weight = makeScalar(); + path.rConicTo(pt[0].fX, pt[0].fY, pt[1].fX, pt[1].fY, weight); + validate(path); + } break; + case kCubicToPath: { + SkPoint pt[3]; + makePointArray(SK_ARRAY_COUNT(pt), pt); + path.cubicTo(pt[0], pt[1], pt[2]); + validate(path); + } break; + case kRCubicToPath: { + SkPoint pt[3]; + makePointArray(SK_ARRAY_COUNT(pt), pt); + path.rCubicTo(pt[0].fX, pt[0].fY, pt[1].fX, pt[1].fY, pt[2].fX, pt[2].fY); + validate(path); + } break; + case kArcToPath: { + SkPoint pt[2]; + makePointArray(SK_ARRAY_COUNT(pt), pt); + SkScalar radius = makeScalar(); + path.arcTo(pt[0], pt[1], radius); + validate(path); + } break; + case kArcTo2Path: { + SkRect oval = makeRect(); + SkScalar startAngle = makeAngle(); + SkScalar sweepAngle = makeAngle(); + bool forceMoveTo = makeBool(); + path.arcTo(oval, startAngle, sweepAngle, forceMoveTo); + validate(path); + } break; + case kClosePath: + path.close(); + validate(path); + break; + } + } + } + return path; +} + +uint32_t makeSegmentCount() { + return fRand.nextRangeU(1, fPathSegmentLimit); +} + +RandomSetRRect makeSetRRectType() { + return (RandomSetRRect) fRand.nextRangeU(0, kRandomSetRRect_Last); +} + +SkScalar makeScalar() { + SkScalar scalar; + scalar = fRand.nextRangeF(fFloatMin, fFloatMax); + return scalar; +} + +void makeScalarArray(size_t arrayCount, SkScalar* array) { + for (size_t index = 0; index < arrayCount; ++index) { + array[index] = makeScalar(); + } +} + +void makeVectorArray(size_t arrayCount, SkVector* array) { + for (size_t index = 0; index < arrayCount; ++index) { + array[index] = makeVector(); + } +} + +SkVector makeVector() { + SkVector result; + makeScalarArray(2, &result.fX); + return result; +} + +void validate(const SkPath& path) { + if (fValidate) { + SkDEBUGCODE(path.experimentalValidateRef()); + } +} + +SkRandom fRand; +SkMatrix fMatrix; +SkPath fClip; +SkPaint fPaint; +SkPath fPath; +SkScalar fFloatMin; +SkScalar fFloatMax; +uint32_t fPathContourCount; +int fPathDepth; +int fPathDepthLimit; +uint32_t fPathSegmentLimit; +int fAddCount; +bool fPrintName; +bool fValidate; +const char* fTab; +}; + +////////////////////////////////////////////////////////////////////////////// +static bool contains_only_moveTo(const SkPath& path) { + int verbCount = path.countVerbs(); + if (verbCount == 0) { + return true; + } + SkTDArray<uint8_t> verbs; + verbs.setCount(verbCount); + SkDEBUGCODE(int getVerbResult = ) path.getVerbs(verbs.begin(), verbCount); + SkASSERT(getVerbResult == verbCount); + for (int index = 0; index < verbCount; ++index) { + if (verbs[index] != SkPath::kMove_Verb) { + return false; + } + } + return true; +} + +class PathFuzzView : public SampleView { +public: + PathFuzzView() { + fDots = 0; + } +protected: + // overrides from SkEventSink + virtual bool onQuery(SkEvent* evt) { + if (SampleCode::TitleQ(*evt)) { + SampleCode::TitleR(evt, "PathFuzzer"); + return true; + } + return this->INHERITED::onQuery(evt); + } + + virtual void onDrawContent(SkCanvas* canvas) { + fuzzPath.randomize(); + const SkPath& path = fuzzPath.getPath(); + const SkPaint& paint = fuzzPath.getPaint(); + const SkPath& clip = fuzzPath.getClip(); + const SkMatrix& matrix = fuzzPath.getMatrix(); + if (!contains_only_moveTo(clip)) { + canvas->clipPath(clip); + } + canvas->setMatrix(matrix); + canvas->drawPath(path, paint); + this->inval(NULL); + if (++fDots == 8000) { + SkDebugf("\n"); + fDots = 0; + } + if ((fDots % 100) == 99) { + SkDebugf("."); + } + } + +private: + FuzzPath fuzzPath; + int fDots; + typedef SkView INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +static SkView* MyFactory() { return new PathFuzzView; } +static SkViewRegister reg(MyFactory); |
