blob: 3b44d7ceb34db75069cfa8de102454b96e5fba91 [file] [log] [blame]
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "gm/gm.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkColor.h"
#include "include/core/SkMatrix.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPathBuilder.h"
#include "include/core/SkRRect.h"
#include "include/core/SkRect.h"
#include "include/core/SkScalar.h"
#include "include/core/SkSize.h"
#include "include/core/SkString.h"
#include "include/core/SkTypes.h"
#include "include/private/base/SkTArray.h"
#include "src/base/SkRandom.h"
using namespace skia_private;
namespace {
class SkDoOnce {
public:
SkDoOnce() { fDidOnce = false; }
// Make noncopyable
SkDoOnce(SkDoOnce&) = delete;
SkDoOnce& operator=(SkDoOnce&) = delete;
bool needToDo() const { return !fDidOnce; }
bool alreadyDone() const { return fDidOnce; }
void accomplished() {
SkASSERT(!fDidOnce);
fDidOnce = true;
}
private:
bool fDidOnce;
};
class ConvexPathsGM : public skiagm::GM {
SkDoOnce fOnce;
void onOnceBeforeDraw() override { this->setBGColor(0xFF000000); }
SkString onShortName() override { return SkString("convexpaths"); }
SkISize onISize() override { return {1200, 1100}; }
void makePaths() {
if (fOnce.alreadyDone()) {
return;
}
fOnce.accomplished();
SkPathBuilder b;
fPaths.push_back(b.moveTo(0, 0)
.quadTo(50, 100, 0, 100)
.lineTo(0, 0)
.detach());
fPaths.push_back(b.moveTo(0, 50)
.quadTo(50, 0, 100, 50)
.quadTo(50, 100, 0, 50)
.detach());
fPaths.push_back(SkPath::Rect({0, 0, 100, 100}, SkPathDirection::kCW));
fPaths.push_back(SkPath::Rect({0, 0, 100, 100}, SkPathDirection::kCCW));
fPaths.push_back(SkPath::Circle(50, 50, 50, SkPathDirection::kCW));
fPaths.push_back(SkPath::Oval(SkRect::MakeXYWH(0, 0, 50, 100), SkPathDirection::kCW));
fPaths.push_back(SkPath::Oval(SkRect::MakeXYWH(0, 0, 100, 5), SkPathDirection::kCCW));
fPaths.push_back(SkPath::Oval(SkRect::MakeXYWH(0, 0, 1, 100), SkPathDirection::kCCW));
fPaths.push_back(SkPath::RRect(SkRRect::MakeRectXY({0, 0, 100, 100}, 40, 20),
SkPathDirection::kCW));
// large number of points
enum {
kLength = 100,
kPtsPerSide = (1 << 12),
};
b.moveTo(0, 0);
for (int i = 1; i < kPtsPerSide; ++i) { // skip the first point due to moveTo.
b.lineTo(kLength * SkIntToScalar(i) / kPtsPerSide, 0);
}
for (int i = 0; i < kPtsPerSide; ++i) {
b.lineTo(kLength, kLength * SkIntToScalar(i) / kPtsPerSide);
}
for (int i = kPtsPerSide; i > 0; --i) {
b.lineTo(kLength * SkIntToScalar(i) / kPtsPerSide, kLength);
}
for (int i = kPtsPerSide; i > 0; --i) {
b.lineTo(0, kLength * SkIntToScalar(i) / kPtsPerSide);
}
fPaths.push_back(b.detach());
// shallow diagonals
fPaths.push_back(SkPath::Polygon({{0,0}, {100,1}, {98,100}, {3,96}}, false));
fPaths.push_back(b.arcTo(SkRect::MakeXYWH(0, 0, 50, 100), 25, 130, false)
.detach());
// cubics
fPaths.push_back(b.cubicTo( 1, 1, 10, 90, 0, 100).detach());
fPaths.push_back(b.cubicTo(100, 50, 20, 100, 0, 0).detach());
// path that has a cubic with a repeated first control point and
// a repeated last control point.
fPaths.push_back(b.moveTo(10, 10)
.cubicTo(10, 10, 10, 0, 20, 0)
.lineTo(40, 0)
.cubicTo(40, 0, 50, 0, 50, 10)
.detach());
// path that has two cubics with repeated middle control points.
fPaths.push_back(b.moveTo(10, 10)
.cubicTo(10, 0, 10, 0, 20, 0)
.lineTo(40, 0)
.cubicTo(50, 0, 50, 0, 50, 10)
.detach());
// cubic where last three points are almost a line
fPaths.push_back(b.moveTo(0, 228.0f/8)
.cubicTo( 628.0f/ 8, 82.0f/8,
1255.0f/ 8, 141.0f/8,
1883.0f/ 8, 202.0f/8)
.detach());
// flat cubic where the at end point tangents both point outward.
fPaths.push_back(b.moveTo(10, 0)
.cubicTo(0, 1, 30, 1, 20, 0)
.detach());
// flat cubic where initial tangent is in, end tangent out
fPaths.push_back(b.moveTo(0, 0)
.cubicTo(10, 1, 30, 1, 20, 0)
.detach());
// flat cubic where initial tangent is out, end tangent in
fPaths.push_back(b.moveTo(10, 0)
.cubicTo(0, 1, 20, 1, 30, 0)
.detach());
// triangle where one edge is a degenerate quad
fPaths.push_back(b.moveTo(8.59375f, 45)
.quadTo(16.9921875f, 45,
31.25f, 45)
.lineTo(100, 100)
.lineTo(8.59375f, 45)
.detach());
// triangle where one edge is a quad with a repeated point
fPaths.push_back(b.moveTo(0, 25)
.lineTo(50, 0)
.quadTo(50, 50, 50, 50)
.detach());
// triangle where one edge is a cubic with a 2x repeated point
fPaths.push_back(b.moveTo(0, 25)
.lineTo(50, 0)
.cubicTo(50, 0, 50, 50, 50, 50)
.detach());
// triangle where one edge is a quad with a nearly repeated point
fPaths.push_back(b.moveTo(0, 25)
.lineTo(50, 0)
.quadTo(50, 49.95f, 50, 50)
.detach());
// triangle where one edge is a cubic with a 3x nearly repeated point
fPaths.push_back(b.moveTo(0, 25)
.lineTo(50, 0)
.cubicTo(50, 49.95f, 50, 49.97f, 50, 50)
.detach());
// triangle where there is a point degenerate cubic at one corner
fPaths.push_back(b.moveTo(0, 25)
.lineTo(50, 0)
.lineTo(50, 50)
.cubicTo(50, 50, 50, 50, 50, 50)
.detach());
// point line
fPaths.push_back(SkPath::Line({50, 50}, {50, 50}));
// point quad
fPaths.push_back(b.moveTo(50, 50)
.quadTo(50, 50, 50, 50)
.detach());
// point cubic
fPaths.push_back(b.moveTo(50, 50)
.cubicTo(50, 50, 50, 50, 50, 50)
.detach());
// moveTo only paths
fPaths.push_back(b.moveTo(0, 0)
.moveTo(0, 0)
.moveTo(1, 1)
.moveTo(1, 1)
.moveTo(10, 10)
.detach());
fPaths.push_back(b.moveTo(0, 0)
.moveTo(0, 0)
.detach());
// line degenerate
fPaths.push_back(b.lineTo(100, 100).detach());
fPaths.push_back(b.quadTo(100, 100, 0, 0).detach());
fPaths.push_back(b.quadTo(100, 100, 50, 50).detach());
fPaths.push_back(b.quadTo(50, 50, 100, 100).detach());
fPaths.push_back(b.cubicTo(0, 0, 0, 0, 100, 100).detach());
// skbug.com/8928
fPaths.push_back(b.moveTo(16.875f, 192.594f)
.cubicTo(45.625f, 192.594f, 74.375f, 192.594f, 103.125f, 192.594f)
.cubicTo(88.75f, 167.708f, 74.375f, 142.823f, 60, 117.938f)
.cubicTo(45.625f, 142.823f, 31.25f, 167.708f, 16.875f, 192.594f)
.close()
.detach());
SkMatrix m;
m.setAll(0.1f, 0, -1, 0, 0.115207f, -2.64977f, 0, 0, 1);
fPaths.back().transform(m);
// small circle. This is listed last so that it has device coords far
// from the origin (small area relative to x,y values).
fPaths.push_back(SkPath::Circle(0, 0, 1.2f));
}
void onDraw(SkCanvas* canvas) override {
this->makePaths();
SkPaint paint;
paint.setAntiAlias(true);
SkRandom rand;
canvas->translate(20, 20);
// As we've added more paths this has gotten pretty big. Scale the whole thing down.
canvas->scale(2.0f/3, 2.0f/3);
for (int i = 0; i < fPaths.size(); ++i) {
canvas->save();
// position the path, and make it at off-integer coords.
canvas->translate(200.0f * (i % 5) + 1.0f/10,
200.0f * (i / 5) + 9.0f/10);
SkColor color = rand.nextU();
color |= 0xff000000;
paint.setColor(color);
#if 0 // This hitting on 32bit Linux builds for some paths. Temporarily disabling while it is
// debugged.
SkASSERT(fPaths[i].isConvex());
#endif
canvas->drawPath(fPaths[i], paint);
canvas->restore();
}
}
TArray<SkPath> fPaths;
};
} // namespace
DEF_GM( return new ConvexPathsGM; )