diff options
author | 2013-09-03 21:28:55 +0000 | |
---|---|---|
committer | 2013-09-03 21:28:55 +0000 | |
commit | 106655efdf2516f7084c19d6d5a7bc59fd8b866c (patch) | |
tree | 92becfd7326250f0f7165a4acbc5764f5507426b | |
parent | 25f72ed03485f58998846d80858d64b5a3c40c7f (diff) |
Fix convex path renderer bounds computation
R=jvanverth@google.com
Author: bsalomon@google.com
Review URL: https://chromiumcodereview.appspot.com/23905005
git-svn-id: http://skia.googlecode.com/svn/trunk@11069 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r-- | src/gpu/GrAAConvexPathRenderer.cpp | 45 |
1 files changed, 29 insertions, 16 deletions
diff --git a/src/gpu/GrAAConvexPathRenderer.cpp b/src/gpu/GrAAConvexPathRenderer.cpp index 59529c5f8b..e50e6b406e 100644 --- a/src/gpu/GrAAConvexPathRenderer.cpp +++ b/src/gpu/GrAAConvexPathRenderer.cpp @@ -218,33 +218,44 @@ static inline bool get_direction(const SkPath& path, const SkMatrix& m, SkPath:: return true; } -static inline void add_line_to_segment(const SkPoint& pt, SegmentArray* segments) { +static inline void add_line_to_segment(const SkPoint& pt, + SegmentArray* segments, + SkRect* devBounds) { segments->push_back(); segments->back().fType = Segment::kLine; segments->back().fPts[0] = pt; + devBounds->growToInclude(pt.fX, pt.fY); } -static inline void add_quad_segment(const SkPoint pts[3], SegmentArray* segments) { +static inline bool contains_inclusive(const SkRect& rect, const SkPoint& p) { + return p.fX >= rect.fLeft && p.fX <= rect.fRight && p.fY >= rect.fTop && p.fY <= rect.fBottom; +} +static inline void add_quad_segment(const SkPoint pts[3], + SegmentArray* segments, + SkRect* devBounds) { 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); + add_line_to_segment(pts[2], segments, devBounds); } } else { segments->push_back(); segments->back().fType = Segment::kQuad; segments->back().fPts[0] = pts[1]; segments->back().fPts[1] = pts[2]; + SkASSERT(contains_inclusive(*devBounds, pts[0])); + devBounds->growToInclude(pts + 1, 2); } } static inline void add_cubic_segments(const SkPoint pts[4], SkPath::Direction dir, - SegmentArray* segments) { + SegmentArray* segments, + SkRect* devBounds) { 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, devBounds); } } @@ -253,7 +264,8 @@ static bool get_segments(const SkPath& path, SegmentArray* segments, SkPoint* fanPt, int* vCount, - int* iCount) { + int* iCount, + SkRect* devBounds) { 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 @@ -276,25 +288,26 @@ static bool get_segments(const SkPath& path, case SkPath::kMove_Verb: m.mapPoints(pts, 1); update_degenerate_test(°enerateData, pts[0]); + devBounds->set(pts->fX, pts->fY, pts->fX, pts->fY); break; 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, devBounds); 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, devBounds); 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]); - add_cubic_segments(pts, dir, segments); + add_cubic_segments(pts, dir, segments, devBounds); break; }; case SkPath::kDone_Verb: @@ -645,10 +658,16 @@ bool GrAAConvexPathRenderer::onDrawPath(const SkPath& origPath, SkSTArray<kPreallocSegmentCnt, Segment, true> segments; SkPoint fanPt; - if (!get_segments(*path, viewMatrix, &segments, &fanPt, &vCount, &iCount)) { + // We can't simply use the path bounds because we may degenerate cubics to quads which produces + // new control points outside the original convex hull. + SkRect devBounds; + if (!get_segments(*path, viewMatrix, &segments, &fanPt, &vCount, &iCount, &devBounds)) { return false; } + // Our computed verts should all be within one pixel of the segment control points. + devBounds.outset(SK_Scalar1, SK_Scalar1); + drawState->setVertexAttribs<gPathAttribs>(SK_ARRAY_COUNT(gPathAttribs)); static const int kEdgeAttrIndex = 1; @@ -666,12 +685,6 @@ bool GrAAConvexPathRenderer::onDrawPath(const SkPath& origPath, SkSTArray<kPreallocDrawCnt, Draw, true> draws; create_vertices(segments, fanPt, &draws, verts, idxs); - // This is valid because all the computed verts are within 1 pixel of the path control points. - SkRect devBounds; - devBounds = path->getBounds(); - viewMatrix.mapRect(&devBounds); - devBounds.outset(SK_Scalar1, SK_Scalar1); - // Check devBounds #ifdef SK_DEBUG SkRect tolDevBounds = devBounds; |