}
class BitmapShaderGM : public GM {
-public:
- BitmapShaderGM() {
+protected:
+ void onOnceBeforeDraw() SK_OVERRIDE {
this->setBGColor(SK_ColorGRAY);
draw_bm(&fBitmap);
draw_mask(&fMask);
}
-protected:
virtual SkString onShortName() {
return SkString("bitmapshaders");
}
SkScalar fX1, fX2, fY, fR;
SkPath fCircle1, fCircle2;
-public:
- CircularClipsGM() {
+protected:
+ void onOnceBeforeDraw() SK_OVERRIDE {
fX1 = 80;
fX2 = 120;
fY = 50;
fCircle2.addCircle(fX2, fY, fR, SkPath::kCW_Direction);
}
-protected:
bool runAsBench() const SK_OVERRIDE { return true; }
ComplexClip2GM(Clip clip, bool antiAlias)
: fClip(clip)
, fAntiAlias(antiAlias) {
+ SkScalar xA = 0.65f;
+ SkScalar xF = 50.65f;
+
+ SkScalar yA = 0.65f;
+ SkScalar yF = 50.65f;
+
+ fWidth = xF - xA;
+ fHeight = yF - yA;
+
+ fTotalWidth = kCols * fWidth + SK_Scalar1 * (kCols + 1) * kPadX;
+ fTotalHeight = kRows * fHeight + SK_Scalar1 * (kRows + 1) * kPadY;
+ }
+
+protected:
+ void onOnceBeforeDraw() SK_OVERRIDE {
this->setBGColor(SkColorSetRGB(0xDD,0xA0,0xDD));
// offset the rects a bit so we get antialiasing even in the rect case
SkScalar yE = 40.65f;
SkScalar yF = 50.65f;
- fWidth = xF - xA;
- fHeight = yF - yA;
-
fRects[0].set(xB, yB, xE, yE);
fRRects[0].setRectXY(fRects[0], 7, 7);
fPaths[0].addRoundRect(fRects[0], 5, 5);
fPaths[4].addRoundRect(fRects[4], 5, 5);
fRectColors[4] = SK_ColorCYAN;
- fTotalWidth = kCols * fWidth + SK_Scalar1 * (kCols + 1) * kPadX;
- fTotalHeight = kRows * fHeight + SK_Scalar1 * (kRows + 1) * kPadY;
-
SkRegion::Op ops[] = {
SkRegion::kDifference_Op,
SkRegion::kIntersect_Op,
}
}
-protected:
-
static const int kRows = 5;
static const int kCols = 5;
static const int kPadX = 20;
//
class PictureGM : public skiagm::GM {
public:
- PictureGM() : fPicture(make_picture()) {}
+ PictureGM()
+ : fPicture(NULL)
+ {}
protected:
+ void onOnceBeforeDraw() SK_OVERRIDE {
+ fPicture.reset(make_picture());
+ }
+
SkString onShortName() SK_OVERRIDE {
return SkString("pictures");
}
PictureShaderGM(SkScalar tileSize, SkScalar sceneSize)
: fTileSize(tileSize)
, fSceneSize(sceneSize) {
+ }
- // Build the picture.
+ protected:
+ void onOnceBeforeDraw() SK_OVERRIDE {
+ // Build the picture.
SkPictureRecorder recorder;
- SkCanvas* pictureCanvas = recorder.beginRecording(tileSize, tileSize, NULL, 0);
+ SkCanvas* pictureCanvas = recorder.beginRecording(fTileSize, fTileSize, NULL, 0);
this->drawTile(pictureCanvas);
fPicture.reset(recorder.endRecording());
// Build a reference bitmap.
- fBitmap.allocN32Pixels(SkScalarCeilToInt(tileSize), SkScalarCeilToInt(tileSize));
+ fBitmap.allocN32Pixels(SkScalarCeilToInt(fTileSize), SkScalarCeilToInt(fTileSize));
fBitmap.eraseColor(SK_ColorTRANSPARENT);
SkCanvas bitmapCanvas(fBitmap);
this->drawTile(&bitmapCanvas);
}
-protected:
SkString onShortName() SK_OVERRIDE {
return SkString("pictureshader");
SkPath fCirclePath;
SkRect fRect;
- ShadowsGM() {
+protected:
+ void onOnceBeforeDraw() SK_OVERRIDE {
this->setBGColor(0xFFDDDDDD);
fCirclePath.addCircle(SkIntToScalar(20), SkIntToScalar(20), SkIntToScalar(10) );
fRect.set(SkIntToScalar(10), SkIntToScalar(10),
SkIntToScalar(30), SkIntToScalar(30));
}
-protected:
virtual SkString onShortName() {
return SkString("shadows");
}
SimpleClipGM(SkGeomTypes geomType)
: fGeomType(geomType) {
+ }
+protected:
+ void onOnceBeforeDraw() SK_OVERRIDE {
// offset the rects a bit so we get anti-aliasing in the rect case
fBase.set(100.65f,
100.65f,
INHERITED::setBGColor(0xFFDDDDDD);
}
-protected:
void buildRgn(SkAAClip* clip, SkRegion::Op op) {
clip->setPath(fBasePath, NULL, true);
class Strokes2GM : public skiagm::GM {
SkPath fPath;
-public:
- Strokes2GM() {
+protected:
+ void onOnceBeforeDraw() SK_OVERRIDE {
SkRandom rand;
fPath.moveTo(0, 0);
for (int i = 0; i < 13; i++) {
}
}
-protected:
SkString onShortName() SK_OVERRIDE {
return SkString("strokes_poly");
'../samplecode/SamplePatch.cpp',
'../samplecode/SamplePath.cpp',
'../samplecode/SamplePathClip.cpp',
+ '../samplecode/SamplePathFuzz.cpp',
'../samplecode/SamplePathUtils.cpp',
'../samplecode/SamplePathEffects.cpp',
'../samplecode/SamplePicture.cpp',
#endif
SkDEBUGCODE(void validate() const;)
+ SkDEBUGCODE(void experimentalValidateRef() const { fPathRef->validate(); } )
private:
enum SerializationOffsets {
}
void SampleView::onDraw(SkCanvas* canvas) {
+ if (!fHaveCalledOnceBeforeDraw) {
+ fHaveCalledOnceBeforeDraw = true;
+ this->onOnceBeforeDraw();
+ }
this->onDrawBackground(canvas);
for (int i = 0; i < fRepeatCount; i++) {
: fPipeState(SkOSMenu::kOffState)
, fBGColor(SK_ColorWHITE)
, fRepeatCount(1)
+ , fHaveCalledOnceBeforeDraw(false)
{}
void setBGColor(SkColor color) { fBGColor = color; }
virtual void onDrawBackground(SkCanvas*);
virtual void onDrawContent(SkCanvas*) = 0;
virtual bool onAnimate(const SkAnimTimer&) { return false; }
+ virtual void onOnceBeforeDraw() {}
// overrides
virtual bool onEvent(const SkEvent& evt);
private:
int fRepeatCount;
-
+ bool fHaveCalledOnceBeforeDraw;
typedef SkView INHERITED;
};
public:
PathEffectView() : fPhase(0) {
+ }
+
+protected:
+ void onOnceBeforeDraw() SK_OVERRIDE {
SkRandom rand;
int steps = 20;
SkScalar dist = SkIntToScalar(400);
this->setBGColor(0xFFDDDDDD);
}
-protected:
bool onQuery(SkEvent* evt) SK_OVERRIDE {
if (SampleCode::TitleQ(*evt)) {
SampleCode::TitleR(evt, "PathEffects");
--- /dev/null
+/*
+ * 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);
class StrokePathView : public SampleView {
SkScalar fWidth;
SkPath fPath;
-public:
- StrokePathView() {
+protected:
+ void onOnceBeforeDraw() SK_OVERRIDE {
// test_blur();
fWidth = SkIntToScalar(120);
this->setBGColor(0xFFDDDDDD);
}
-protected:
// overrides from SkEventSink
bool onQuery(SkEvent* evt) SK_OVERRIDE {
if (SampleCode::TitleQ(*evt)) {
SkPath fPath;
SkScalar fHOffset;
- TextOnPathView() {
+protected:
+ void onOnceBeforeDraw() SK_OVERRIDE {
SkRect r;
r.set(SkIntToScalar(100), SkIntToScalar(100),
SkIntToScalar(300), SkIntToScalar(300));
fHOffset = SkIntToScalar(50);
}
-protected:
// overrides from SkEventSink
bool onQuery(SkEvent* evt) SK_OVERRIDE {
if (SampleCode::TitleQ(*evt)) {
if (close) {
ed.growForVerb(kClose_Verb);
+ fLastMoveToIndex ^= ~fLastMoveToIndex >> (8 * sizeof(fLastMoveToIndex) - 1);
}
DIRTY_AFTER_EDIT;
#endif
void finishContour(bool close, bool isLine);
- void preJoinTo(const SkPoint&, SkVector* normal, SkVector* unitNormal,
+ bool preJoinTo(const SkPoint&, SkVector* normal, SkVector* unitNormal,
bool isLine);
void postJoinTo(const SkPoint&, const SkVector& normal,
const SkVector& unitNormal);
///////////////////////////////////////////////////////////////////////////////
-void SkPathStroker::preJoinTo(const SkPoint& currPt, SkVector* normal,
+bool SkPathStroker::preJoinTo(const SkPoint& currPt, SkVector* normal,
SkVector* unitNormal, bool currIsLine) {
SkASSERT(fSegmentCount >= 0);
SkScalar prevX = fPrevPt.fX;
SkScalar prevY = fPrevPt.fY;
- SkAssertResult(set_normal_unitnormal(fPrevPt, currPt, fRadius, normal,
- unitNormal));
+ if (!set_normal_unitnormal(fPrevPt, currPt, fRadius, normal, unitNormal)) {
+ return false;
+ }
if (fSegmentCount == 0) {
fFirstNormal = *normal;
fRadius, fInvMiterLimit, fPrevIsLine, currIsLine);
}
fPrevIsLine = currIsLine;
+ return true;
}
void SkPathStroker::postJoinTo(const SkPoint& currPt, const SkVector& normal,
}
SkVector normal, unitNormal;
- this->preJoinTo(currPt, &normal, &unitNormal, true);
+ if (!this->preJoinTo(currPt, &normal, &unitNormal, true)) {
+ return;
+ }
this->line_to(currPt, normal);
this->postJoinTo(currPt, normal, unitNormal);
}
}
SkASSERT(kQuad_ReductionType == reductionType);
SkVector normalAB, unitAB, normalBC, unitBC;
- this->preJoinTo(pt1, &normalAB, &unitAB, false);
- SkQuadConstruct quadPts;
- this->init(kOuter_StrokeType, &quadPts, 0, 1);
- if (!this->conicStroke(conic, &quadPts)) {
+ if (!this->preJoinTo(pt1, &normalAB, &unitAB, false)) {
+ this->lineTo(pt2);
return;
}
+ SkQuadConstruct quadPts;
+ this->init(kOuter_StrokeType, &quadPts, 0, 1);
+ (void) this->conicStroke(conic, &quadPts);
this->init(kInner_StrokeType, &quadPts, 0, 1);
- if (!this->conicStroke(conic, &quadPts)) {
- return;
- }
+ (void) this->conicStroke(conic, &quadPts);
this->setConicEndNormal(conic, normalAB, unitAB, &normalBC, &unitBC);
this->postJoinTo(pt2, normalBC, unitBC);
}
}
SkASSERT(kQuad_ReductionType == reductionType);
SkVector normalAB, unitAB, normalBC, unitBC;
- this->preJoinTo(pt1, &normalAB, &unitAB, false);
- SkQuadConstruct quadPts;
- this->init(kOuter_StrokeType, &quadPts, 0, 1);
- if (!this->quadStroke(quad, &quadPts)) {
+ if (!this->preJoinTo(pt1, &normalAB, &unitAB, false)) {
+ this->lineTo(pt2);
return;
}
+ SkQuadConstruct quadPts;
+ this->init(kOuter_StrokeType, &quadPts, 0, 1);
+ (void) this->quadStroke(quad, &quadPts);
this->init(kInner_StrokeType, &quadPts, 0, 1);
- if (!this->quadStroke(quad, &quadPts)) {
- return;
- }
+ (void) this->quadStroke(quad, &quadPts);
this->setQuadEndNormal(quad, normalAB, unitAB, &normalBC, &unitBC);
#else
bool degenerateAB = SkPath::IsLineDegenerate(fPrevPt, pt1);
}
SkASSERT(kQuad_ReductionType == reductionType);
SkVector normalAB, unitAB, normalCD, unitCD;
- this->preJoinTo(*tangentPt, &normalAB, &unitAB, false);
+ if (!this->preJoinTo(*tangentPt, &normalAB, &unitAB, false)) {
+ this->lineTo(pt3);
+ return;
+ }
SkScalar tValues[2];
int count = SkFindCubicInflections(cubic, tValues);
SkScalar lastT = 0;
SkScalar nextT = index < count ? tValues[index] : 1;
SkQuadConstruct quadPts;
this->init(kOuter_StrokeType, &quadPts, lastT, nextT);
- if (!this->cubicStroke(cubic, &quadPts)) {
- break;
- }
+ (void) this->cubicStroke(cubic, &quadPts);
this->init(kInner_StrokeType, &quadPts, lastT, nextT);
- if (!this->cubicStroke(cubic, &quadPts)) {
- break;
- }
+ (void) this->cubicStroke(cubic, &quadPts);
lastT = nextT;
}
// emit the join even if one stroke succeeded but the last one failed
SkScalarNearlyEqual(a.bottom(), b.bottom());
}
+static void test_strokecubic(skiatest::Reporter* reporter) {
+ uint32_t hexCubicVals[] = {
+ 0x424c1086, 0x44bcf0cb, // fX=51.0161362 fY=1511.52478
+ 0x424c107c, 0x44bcf0cb, // fX=51.0160980 fY=1511.52478
+ 0x424c10c2, 0x44bcf0cb, // fX=51.0163651 fY=1511.52478
+ 0x424c1119, 0x44bcf0ca, // fX=51.0166969 fY=1511.52466
+ };
+ SkPoint cubicVals[] = {
+ {51.0161362f, 1511.52478f },
+ {51.0160980f, 1511.52478f },
+ {51.0163651f, 1511.52478f },
+ {51.0166969f, 1511.52466f },
+ };
+ SkPaint paint;
+
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(0.394537568f);
+ SkPath path, fillPath;
+ path.moveTo(cubicVals[0]);
+ path.cubicTo(cubicVals[1], cubicVals[2], cubicVals[3]);
+ paint.getFillPath(path, &fillPath);
+ path.reset();
+ path.moveTo(SkBits2Float(hexCubicVals[0]), SkBits2Float(hexCubicVals[1]));
+ path.cubicTo(SkBits2Float(hexCubicVals[2]), SkBits2Float(hexCubicVals[3]),
+ SkBits2Float(hexCubicVals[4]), SkBits2Float(hexCubicVals[5]),
+ SkBits2Float(hexCubicVals[6]), SkBits2Float(hexCubicVals[7]));
+ paint.getFillPath(path, &fillPath);
+}
+
static void test_strokerect(skiatest::Reporter* reporter) {
const SkScalar width = SkIntToScalar(10);
SkPaint paint;
}
DEF_TEST(Stroke, reporter) {
+ test_strokecubic(reporter);
test_strokerect(reporter);
}