Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(203)

Unified Diff: src/gpu/GrAAConvexPathRenderer.cpp

Issue 1094293002: Fix double blend in GrAAConvexPathRenderer (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Combine colinear lines Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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(&degenerateData, 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(&degenerateData, pts[1]);
update_degenerate_test(&degenerateData, 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(&degenerateData, quadPts[2*i + 1]);
update_degenerate_test(&degenerateData, 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(&degenerateData, pts[1]);
update_degenerate_test(&degenerateData, pts[2]);
update_degenerate_test(&degenerateData, 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;
}
}
}
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698