Index: src/gpu/GrAAConvexPathRenderer.cpp |
diff --git a/src/gpu/GrAAConvexPathRenderer.cpp b/src/gpu/GrAAConvexPathRenderer.cpp |
index 1813803d8ad7ea41a7556ee1d32b01c366be8f60..eb0dab967ed3708605370d16d7a5d4e71ca2be40 100644 |
--- a/src/gpu/GrAAConvexPathRenderer.cpp |
+++ b/src/gpu/GrAAConvexPathRenderer.cpp |
@@ -224,18 +224,42 @@ static inline bool get_direction(const SkPath& path, const SkMatrix& m, SkPath:: |
return true; |
} |
robertphillips
2015/04/24 12:32:55
Seems like we should do this in terms of pixels.
bsalomon
2015/04/24 14:19:55
Are we not in device space here?
Chris Dalton
2015/04/24 18:36:27
Doing it in pixels is fine, it just comes at the c
|
+static inline bool are_colinear(const SkPoint& startPt, |
+ const SkPoint& testPt, |
+ const SkPoint& endPt, |
+ SkScalar threshold = 1e-5f) { |
+ // Returns whether the distance from testPt to the line defined by [startPt, endPt] is within |
+ // a fraction of the distance from startPt to endPt. |
+ // TODO: It may (or may not) make more sense for the threshold to instead be in terms of pixels. |
+ SkVector ortho; |
+ ortho.setOrthog(endPt - startPt); |
+ return fabsf(ortho.dot(startPt) - ortho.dot(testPt)) < threshold * ortho.dot(ortho); |
+} |
+ |
static inline void add_line_to_segment(const SkPoint& pt, |
- SegmentArray* segments) { |
+ SegmentArray* segments, |
+ const SkPoint& pathStartPt) { |
+ if (!segments->empty() && Segment::kLine == segments->back().fType) { |
+ const SkPoint& prevLineStartPt = segments->count() > 2 ? |
+ (*segments)[segments->count() - 2].endPt() : pathStartPt; |
+ if (are_colinear(prevLineStartPt, segments->back().fPts[0], pt)) { |
+ // Combine with the previous line, since it is colinear. |
+ segments->back().fPts[0] = pt; |
+ return; |
+ } |
+ } |
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) { |
+ SegmentArray* segments, |
+ const SkPoint& pathStartPt) { |
+ if (pts[0].distanceToSqd(pts[1]) < kCloseSqd || pts[1].distanceToSqd(pts[2]) < kCloseSqd || |
+ are_colinear(pts[0], pts[1], pts[2])) { |
if (pts[0] != pts[2]) { |
- add_line_to_segment(pts[2], segments); |
+ add_line_to_segment(pts[2], segments, pathStartPt); |
} |
} else { |
segments->push_back(); |
@@ -247,12 +271,13 @@ static inline void add_quad_segment(const SkPoint pts[3], |
static inline void add_cubic_segments(const SkPoint pts[4], |
SkPath::Direction dir, |
- SegmentArray* segments) { |
+ SegmentArray* segments, |
+ const SkPoint& pathStartPt) { |
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); |
+ add_quad_segment(&quads[q], segments, pathStartPt); |
} |
} |
@@ -277,9 +302,12 @@ static bool get_segments(const SkPath& path, |
return false; |
} |
+ SkPoint pts[4]; |
+ SkPath::Verb verb = iter.next(pts); |
+ SkPoint pathStartPt; |
+ m.mapPoints(&pathStartPt, pts, 1); |
+ |
for (;;) { |
- SkPoint pts[4]; |
- SkPath::Verb verb = iter.next(pts); |
switch (verb) { |
case SkPath::kMove_Verb: |
m.mapPoints(pts, 1); |
@@ -288,14 +316,14 @@ static bool get_segments(const SkPath& path, |
case SkPath::kLine_Verb: { |
m.mapPoints(&pts[1], 1); |
update_degenerate_test(°enerateData, pts[1]); |
- add_line_to_segment(pts[1], segments); |
+ add_line_to_segment(pts[1], segments, pathStartPt); |
break; |
} |
case SkPath::kQuad_Verb: |
m.mapPoints(pts, 3); |
update_degenerate_test(°enerateData, pts[1]); |
update_degenerate_test(°enerateData, pts[2]); |
- add_quad_segment(pts, segments); |
+ add_quad_segment(pts, segments, pathStartPt); |
break; |
case SkPath::kConic_Verb: { |
m.mapPoints(pts, 3); |
@@ -305,7 +333,7 @@ static bool get_segments(const SkPath& path, |
for (int i = 0; i < converter.countQuads(); ++i) { |
update_degenerate_test(°enerateData, quadPts[2*i + 1]); |
update_degenerate_test(°enerateData, quadPts[2*i + 2]); |
- add_quad_segment(quadPts + 2*i, segments); |
+ add_quad_segment(quadPts + 2*i, segments, pathStartPt); |
} |
break; |
} |
@@ -314,19 +342,30 @@ static bool get_segments(const SkPath& path, |
update_degenerate_test(°enerateData, pts[1]); |
update_degenerate_test(°enerateData, pts[2]); |
update_degenerate_test(°enerateData, pts[3]); |
- add_cubic_segments(pts, dir, segments); |
+ add_cubic_segments(pts, dir, segments, pathStartPt); |
break; |
}; |
case SkPath::kDone_Verb: |
if (degenerateData.isDegenerate()) { |
return false; |
} else { |
+ if (segments->count() > 2 && |
+ Segment::kLine == segments->front().fType && |
+ Segment::kLine == segments->back().fType && |
+ are_colinear((*segments)[segments->count() - 2].endPt(), |
+ pathStartPt, |
+ segments->front().endPt())) { |
+ // First and last lines are colinear. |
+ segments->pop_back(); |
+ } |
compute_vectors(segments, fanPt, dir, vCount, iCount); |
return true; |
} |
default: |
break; |
} |
+ |
+ verb = iter.next(pts); |
} |
} |
@@ -425,20 +464,27 @@ static void create_vertices(const SegmentArray& segments, |
verts[*v + 3].fD0 = verts[*v + 3].fD1 = -SK_Scalar1; |
verts[*v + 4].fD0 = verts[*v + 4].fD1 = -SK_Scalar1; |
- idxs[*i + 0] = *v + 0; |
- idxs[*i + 1] = *v + 2; |
- idxs[*i + 2] = *v + 1; |
+ idxs[*i + 0] = *v + 3; |
+ idxs[*i + 1] = *v + 1; |
+ idxs[*i + 2] = *v + 2; |
- idxs[*i + 3] = *v + 3; |
- idxs[*i + 4] = *v + 1; |
+ idxs[*i + 3] = *v + 4; |
+ idxs[*i + 4] = *v + 3; |
idxs[*i + 5] = *v + 2; |
- idxs[*i + 6] = *v + 4; |
- idxs[*i + 7] = *v + 3; |
- idxs[*i + 8] = *v + 2; |
+ *i += 6; |
+ |
+ // Draw the interior fan if it exists. Colinear line segments have already been combined |
+ // by this point, so we know the fan exists as long as there are at least 3 segments. |
+ if (count >= 3) { |
+ idxs[*i + 0] = *v + 0; |
+ idxs[*i + 1] = *v + 2; |
+ idxs[*i + 2] = *v + 1; |
+ |
+ *i += 3; |
+ } |
*v += 5; |
- *i += 9; |
} else { |
SkPoint qpts[] = {sega.endPt(), segb.fPts[0], segb.fPts[1]}; |
@@ -482,12 +528,19 @@ static void create_vertices(const SegmentArray& segments, |
idxs[*i + 7] = *v + 3; |
idxs[*i + 8] = *v + 4; |
- idxs[*i + 9] = *v + 0; |
- idxs[*i + 10] = *v + 2; |
- idxs[*i + 11] = *v + 1; |
+ *i += 9; |
+ |
+ // Draw the interior fan if it exists. Colinear line segments have already been combined |
+ // by this point, so we know the fan exists as long as there are at least 3 segments. |
+ if (count >= 3) { |
+ idxs[*i + 0] = *v + 0; |
+ idxs[*i + 1] = *v + 2; |
+ idxs[*i + 2] = *v + 1; |
+ |
+ *i += 3; |
+ } |
*v += 6; |
- *i += 12; |
} |
} |
} |