Fix repeated point quads/cubics in convex pr and update convexpaths GM
R=robertphillips@google.com, jvanverth@google.com
Author: bsalomon@google.com
Review URL: https://chromiumcodereview.appspot.com/23034003
git-svn-id: http://skia.googlecode.com/svn/trunk@10744 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gm/convexpaths.cpp b/gm/convexpaths.cpp
index a354bd4..4b3c7b6 100644
--- a/gm/convexpaths.cpp
+++ b/gm/convexpaths.cpp
@@ -48,32 +48,18 @@
return;
}
fOnce.accomplished();
- // CW
+
fPaths.push_back().moveTo(0, 0);
fPaths.back().quadTo(50 * SK_Scalar1, 100 * SK_Scalar1,
0, 100 * SK_Scalar1);
fPaths.back().lineTo(0, 0);
- // CCW
- fPaths.push_back().moveTo(0, 0);
- fPaths.back().lineTo(0, 100 * SK_Scalar1);
- fPaths.back().quadTo(50 * SK_Scalar1, 100 * SK_Scalar1,
- 0, 0);
-
- // CW
fPaths.push_back().moveTo(0, 50 * SK_Scalar1);
fPaths.back().quadTo(50 * SK_Scalar1, 0,
100 * SK_Scalar1, 50 * SK_Scalar1);
fPaths.back().quadTo(50 * SK_Scalar1, 100 * SK_Scalar1,
0, 50 * SK_Scalar1);
- // CCW
- fPaths.push_back().moveTo(0, 50 * SK_Scalar1);
- fPaths.back().quadTo(50 * SK_Scalar1, 100 * SK_Scalar1,
- 100 * SK_Scalar1, 50 * SK_Scalar1);
- fPaths.back().quadTo(50 * SK_Scalar1, 0,
- 0, 50 * SK_Scalar1);
-
fPaths.push_back().addRect(0, 0,
100 * SK_Scalar1, 100 * SK_Scalar1,
SkPath::kCW_Direction);
@@ -85,8 +71,6 @@
fPaths.push_back().addCircle(50 * SK_Scalar1, 50 * SK_Scalar1,
50 * SK_Scalar1, SkPath::kCW_Direction);
- fPaths.push_back().addCircle(50 * SK_Scalar1, 50 * SK_Scalar1,
- 40 * SK_Scalar1, SkPath::kCCW_Direction);
fPaths.push_back().addOval(SkRect::MakeXYWH(0, 0,
50 * SK_Scalar1,
@@ -95,18 +79,13 @@
fPaths.push_back().addOval(SkRect::MakeXYWH(0, 0,
100 * SK_Scalar1,
- 50 * SK_Scalar1),
- SkPath::kCCW_Direction);
-
- fPaths.push_back().addOval(SkRect::MakeXYWH(0, 0,
- 100 * SK_Scalar1,
5 * SK_Scalar1),
SkPath::kCCW_Direction);
fPaths.push_back().addOval(SkRect::MakeXYWH(0, 0,
SK_Scalar1,
100 * SK_Scalar1),
- SkPath::kCCW_Direction);
+ SkPath::kCCW_Direction);
fPaths.push_back().addRoundRect(SkRect::MakeXYWH(0, 0,
SK_Scalar1 * 100,
@@ -114,12 +93,6 @@
40 * SK_Scalar1, 20 * SK_Scalar1,
SkPath::kCW_Direction);
- fPaths.push_back().addRoundRect(SkRect::MakeXYWH(0, 0,
- SK_Scalar1 * 100,
- SK_Scalar1 * 100),
- 20 * SK_Scalar1, 40 * SK_Scalar1,
- SkPath::kCCW_Direction);
-
// large number of points
enum {
kLength = 100,
@@ -144,12 +117,10 @@
fPaths.back().lineTo(98 * SK_Scalar1, 100 * SK_Scalar1);
fPaths.back().lineTo(3 * SK_Scalar1, 96 * SK_Scalar1);
- //It turns out arcTos are not automatically marked as convex and they
- //may in fact be ever so slightly concave.
- //fPaths.push_back().arcTo(SkRect::MakeXYWH(0, 0,
- // 50 * SK_Scalar1,
- // 100 * SK_Scalar1),
- // 25 * SK_Scalar1, 130 * SK_Scalar1, false);
+ fPaths.push_back().arcTo(SkRect::MakeXYWH(0, 0,
+ 50 * SK_Scalar1,
+ 100 * SK_Scalar1),
+ 25 * SK_Scalar1, 130 * SK_Scalar1, false);
// cubics
fPaths.push_back().cubicTo( 1 * SK_Scalar1, 1 * SK_Scalar1,
@@ -211,13 +182,49 @@
fPaths.back().lineTo(100 * SK_Scalar1, 100 * SK_Scalar1);
fPaths.back().lineTo(SkFloatToScalar(8.59375f), 45 * SK_Scalar1);
- // point degenerate
+ // triangle where one edge is a quad with a repeated point
+ fPaths.push_back().moveTo(0, 25 * SK_Scalar1);
+ fPaths.back().lineTo(50 * SK_Scalar1, 0);
+ fPaths.back().quadTo(50 * SK_Scalar1, 50 * SK_Scalar1, 50 * SK_Scalar1, 50 * SK_Scalar1);
+
+ // triangle where one edge is a cubic with a 2x repeated point
+ fPaths.push_back().moveTo(0, 25 * SK_Scalar1);
+ fPaths.back().lineTo(50 * SK_Scalar1, 0);
+ fPaths.back().cubicTo(50 * SK_Scalar1, 0,
+ 50 * SK_Scalar1, 50 * SK_Scalar1,
+ 50 * SK_Scalar1, 50 * SK_Scalar1);
+
+ // triangle where one edge is a quad with a nearly repeated point
+ fPaths.push_back().moveTo(0, 25 * SK_Scalar1);
+ fPaths.back().lineTo(50 * SK_Scalar1, 0);
+ fPaths.back().quadTo(50 * SK_Scalar1, SkFloatToScalar(49.95f),
+ 50 * SK_Scalar1, 50 * SK_Scalar1);
+
+ // triangle where one edge is a cubic with a 3x nearly repeated point
+ fPaths.push_back().moveTo(0, 25 * SK_Scalar1);
+ fPaths.back().lineTo(50 * SK_Scalar1, 0);
+ fPaths.back().cubicTo(50 * SK_Scalar1, SkFloatToScalar(49.95f),
+ 50 * SK_Scalar1, SkFloatToScalar(49.97f),
+ 50 * SK_Scalar1, 50 * SK_Scalar1);
+
+ // triangle where there is a point degenerate cubic at one corner
+ fPaths.push_back().moveTo(0, 25 * SK_Scalar1);
+ fPaths.back().lineTo(50 * SK_Scalar1, 0);
+ fPaths.back().lineTo(50 * SK_Scalar1, 50 * SK_Scalar1);
+ fPaths.back().cubicTo(50 * SK_Scalar1, 50 * SK_Scalar1,
+ 50 * SK_Scalar1, 50 * SK_Scalar1,
+ 50 * SK_Scalar1, 50 * SK_Scalar1);
+
+ // point line
fPaths.push_back().moveTo(50 * SK_Scalar1, 50 * SK_Scalar1);
fPaths.back().lineTo(50 * SK_Scalar1, 50 * SK_Scalar1);
+ // point quad
fPaths.push_back().moveTo(50 * SK_Scalar1, 50 * SK_Scalar1);
fPaths.back().quadTo(50 * SK_Scalar1, 50 * SK_Scalar1,
50 * SK_Scalar1, 50 * SK_Scalar1);
+
+ // point cubic
fPaths.push_back().moveTo(50 * SK_Scalar1, 50 * SK_Scalar1);
fPaths.back().cubicTo(50 * SK_Scalar1, 50 * SK_Scalar1,
50 * SK_Scalar1, 50 * SK_Scalar1,
@@ -246,7 +253,7 @@
// 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().addCircle(0, 0, SkFloatToScalar(0.8f));
+ fPaths.push_back().addCircle(0, 0, SkFloatToScalar(1.2f));
}
virtual void onDraw(SkCanvas* canvas) {
@@ -256,11 +263,15 @@
paint.setAntiAlias(true);
SkRandom rand;
canvas->translate(20 * SK_Scalar1, 20 * SK_Scalar1);
+
+ // As we've added more paths this has gotten pretty big. Scale the whole thing down.
+ canvas->scale(2 * SK_Scalar1 / 3, 2 * SK_Scalar1 / 3);
+
for (int i = 0; i < fPaths.count(); ++i) {
canvas->save();
// position the path, and make it at off-integer coords.
- canvas->translate(SK_Scalar1 * 200 * (i % 5) + SK_Scalar1 / 4,
- SK_Scalar1 * 200 * (i / 5) + 3 * SK_Scalar1 / 4);
+ canvas->translate(SK_Scalar1 * 200 * (i % 5) + SK_Scalar1 / 10,
+ SK_Scalar1 * 200 * (i / 5) + 9 * SK_Scalar1 / 10);
SkColor color = rand.nextU();
color |= 0xff000000;
paint.setColor(color);
diff --git a/src/gpu/GrAAConvexPathRenderer.cpp b/src/gpu/GrAAConvexPathRenderer.cpp
index 408fcb5..47315a4 100644
--- a/src/gpu/GrAAConvexPathRenderer.cpp
+++ b/src/gpu/GrAAConvexPathRenderer.cpp
@@ -24,8 +24,6 @@
GrAAConvexPathRenderer::GrAAConvexPathRenderer() {
}
-namespace {
-
struct Segment {
enum {
// These enum values are assumed in member functions below.
@@ -57,7 +55,7 @@
typedef SkTArray<Segment, true> SegmentArray;
-void center_of_mass(const SegmentArray& segments, SkPoint* c) {
+static void center_of_mass(const SegmentArray& segments, SkPoint* c) {
SkScalar area = 0;
SkPoint center = {0, 0};
int count = segments.count();
@@ -108,11 +106,11 @@
GrAssert(!SkScalarIsNaN(c->fX) && !SkScalarIsNaN(c->fY));
}
-void compute_vectors(SegmentArray* segments,
- SkPoint* fanPt,
- SkPath::Direction dir,
- int* vCount,
- int* iCount) {
+static void compute_vectors(SegmentArray* segments,
+ SkPoint* fanPt,
+ SkPath::Direction dir,
+ int* vCount,
+ int* iCount) {
center_of_mass(*segments, fanPt);
int count = segments->count();
@@ -177,17 +175,17 @@
SkScalar fLineC;
};
-void update_degenerate_test(DegenerateTestData* data, const GrPoint& pt) {
- static const SkScalar TOL = (SK_Scalar1 / 16);
- static const SkScalar TOL_SQD = SkScalarMul(TOL, TOL);
+static const SkScalar kClose = (SK_Scalar1 / 16);
+static const SkScalar kCloseSqd = SkScalarMul(kClose, kClose);
+static void update_degenerate_test(DegenerateTestData* data, const GrPoint& pt) {
switch (data->fStage) {
case DegenerateTestData::kInitial:
data->fFirstPoint = pt;
data->fStage = DegenerateTestData::kPoint;
break;
case DegenerateTestData::kPoint:
- if (pt.distanceToSqd(data->fFirstPoint) > TOL_SQD) {
+ if (pt.distanceToSqd(data->fFirstPoint) > kCloseSqd) {
data->fLineNormal = pt - data->fFirstPoint;
data->fLineNormal.normalize();
data->fLineNormal.setOrthog(data->fLineNormal);
@@ -196,7 +194,7 @@
}
break;
case DegenerateTestData::kLine:
- if (SkScalarAbs(data->fLineNormal.dot(pt) + data->fLineC) > TOL) {
+ if (SkScalarAbs(data->fLineNormal.dot(pt) + data->fLineC) > kClose) {
data->fStage = DegenerateTestData::kNonDegenerate;
}
case DegenerateTestData::kNonDegenerate:
@@ -206,7 +204,7 @@
}
}
-inline bool get_direction(const SkPath& path, const SkMatrix& m, SkPath::Direction* dir) {
+static inline bool get_direction(const SkPath& path, const SkMatrix& m, SkPath::Direction* dir) {
if (!path.cheapComputeDirection(dir)) {
return false;
}
@@ -220,12 +218,42 @@
return true;
}
-bool get_segments(const SkPath& path,
- const SkMatrix& m,
- SegmentArray* segments,
- SkPoint* fanPt,
- int* vCount,
- int* iCount) {
+static inline void add_line_to_segment(const SkPoint& pt, SegmentArray* segments) {
+ segments->push_back();
+ segments->back().fType = Segment::kLine;
+ segments->back().fPts[0] = pt;
+}
+
+static inline void add_quad_segment(const SkPoint pts[3], SegmentArray* segments) {
+ if (pts[0].distanceToSqd(pts[1]) < kCloseSqd || pts[1].distanceToSqd(pts[2]) < kCloseSqd) {
+ if (pts[0] != pts[2]) {
+ add_line_to_segment(pts[2], segments);
+ }
+ } else {
+ segments->push_back();
+ segments->back().fType = Segment::kQuad;
+ segments->back().fPts[0] = pts[1];
+ segments->back().fPts[1] = pts[2];
+ }
+}
+
+static inline void add_cubic_segments(const SkPoint pts[4],
+ SkPath::Direction dir,
+ SegmentArray* segments) {
+ SkSTArray<15, SkPoint, true> quads;
+ GrPathUtils::convertCubicToQuads(pts, SK_Scalar1, true, dir, &quads);
+ int count = quads.count();
+ for (int q = 0; q < count; q += 3) {
+ add_quad_segment(&quads[q], segments);
+ }
+}
+
+static bool get_segments(const SkPath& path,
+ const SkMatrix& m,
+ SegmentArray* segments,
+ SkPoint* fanPt,
+ int* vCount,
+ int* iCount) {
SkPath::Iter iter(path, true);
// This renderer over-emphasizes very thin path regions. We use the distance
// to the path from the sample to compute coverage. Every pixel intersected
@@ -250,38 +278,23 @@
update_degenerate_test(°enerateData, pts[0]);
break;
case SkPath::kLine_Verb: {
- m.mapPoints(pts + 1, 1);
+ m.mapPoints(&pts[1], 1);
update_degenerate_test(°enerateData, pts[1]);
- segments->push_back();
- segments->back().fType = Segment::kLine;
- segments->back().fPts[0] = pts[1];
+ add_line_to_segment(pts[1], segments);
break;
}
case SkPath::kQuad_Verb:
- m.mapPoints(pts + 1, 2);
+ m.mapPoints(pts, 3);
update_degenerate_test(°enerateData, pts[1]);
update_degenerate_test(°enerateData, pts[2]);
- segments->push_back();
- segments->back().fType = Segment::kQuad;
- segments->back().fPts[0] = pts[1];
- segments->back().fPts[1] = pts[2];
+ add_quad_segment(pts, segments);
break;
case SkPath::kCubic_Verb: {
m.mapPoints(pts, 4);
update_degenerate_test(°enerateData, pts[1]);
update_degenerate_test(°enerateData, pts[2]);
update_degenerate_test(°enerateData, pts[3]);
- // unlike quads and lines, the pts[0] will also be read (in
- // convertCubicToQuads).
- SkSTArray<15, SkPoint, true> quads;
- GrPathUtils::convertCubicToQuads(pts, SK_Scalar1, true, dir, &quads);
- int count = quads.count();
- for (int q = 0; q < count; q += 3) {
- segments->push_back();
- segments->back().fType = Segment::kQuad;
- segments->back().fPts[0] = quads[q + 1];
- segments->back().fPts[1] = quads[q + 2];
- }
+ add_cubic_segments(pts, dir, segments);
break;
};
case SkPath::kDone_Verb:
@@ -312,11 +325,11 @@
typedef SkTArray<Draw, true> DrawArray;
-void create_vertices(const SegmentArray& segments,
- const SkPoint& fanPt,
- DrawArray* draws,
- QuadVertex* verts,
- uint16_t* idxs) {
+static void create_vertices(const SegmentArray& segments,
+ const SkPoint& fanPt,
+ DrawArray* draws,
+ QuadVertex* verts,
+ uint16_t* idxs) {
Draw* draw = &draws->push_back();
// alias just to make vert/index assignments easier to read.
int* v = &draw->fVertexCnt;
@@ -459,8 +472,6 @@
}
}
-}
-
///////////////////////////////////////////////////////////////////////////////
/*