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

Side by Side Diff: src/gpu/GrAAConvexPathRenderer.cpp

Issue 23905005: Fix convex path renderer bounds computation (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: Created 7 years, 3 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 1
2 /* 2 /*
3 * Copyright 2012 Google Inc. 3 * Copyright 2012 Google Inc.
4 * 4 *
5 * Use of this source code is governed by a BSD-style license that can be 5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file. 6 * found in the LICENSE file.
7 */ 7 */
8 8
9 #include "GrAAConvexPathRenderer.h" 9 #include "GrAAConvexPathRenderer.h"
10 10
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after
211 // check whether m reverses the orientation 211 // check whether m reverses the orientation
212 SkASSERT(!m.hasPerspective()); 212 SkASSERT(!m.hasPerspective());
213 SkScalar det2x2 = SkScalarMul(m.get(SkMatrix::kMScaleX), m.get(SkMatrix::kMS caleY)) - 213 SkScalar det2x2 = SkScalarMul(m.get(SkMatrix::kMScaleX), m.get(SkMatrix::kMS caleY)) -
214 SkScalarMul(m.get(SkMatrix::kMSkewX), m.get(SkMatrix::kMSk ewY)); 214 SkScalarMul(m.get(SkMatrix::kMSkewX), m.get(SkMatrix::kMSk ewY));
215 if (det2x2 < 0) { 215 if (det2x2 < 0) {
216 *dir = SkPath::OppositeDirection(*dir); 216 *dir = SkPath::OppositeDirection(*dir);
217 } 217 }
218 return true; 218 return true;
219 } 219 }
220 220
221 static inline void add_line_to_segment(const SkPoint& pt, SegmentArray* segments ) { 221 static inline void add_line_to_segment(const SkPoint& pt,
222 SegmentArray* segments,
223 SkRect* devBounds) {
222 segments->push_back(); 224 segments->push_back();
223 segments->back().fType = Segment::kLine; 225 segments->back().fType = Segment::kLine;
224 segments->back().fPts[0] = pt; 226 segments->back().fPts[0] = pt;
227 devBounds->growToInclude(pt.fX, pt.fY);
225 } 228 }
226 229
227 static inline void add_quad_segment(const SkPoint pts[3], SegmentArray* segments ) { 230 static inline bool contains_inclusive(const SkRect& rect, const SkPoint& p) {
231 return p.fX >= rect.fLeft && p.fX <= rect.fRight && p.fY >= rect.fTop && p.f Y <= rect.fBottom;
232 }
233 static inline void add_quad_segment(const SkPoint pts[3],
234 SegmentArray* segments,
235 SkRect* devBounds) {
228 if (pts[0].distanceToSqd(pts[1]) < kCloseSqd || pts[1].distanceToSqd(pts[2]) < kCloseSqd) { 236 if (pts[0].distanceToSqd(pts[1]) < kCloseSqd || pts[1].distanceToSqd(pts[2]) < kCloseSqd) {
229 if (pts[0] != pts[2]) { 237 if (pts[0] != pts[2]) {
230 add_line_to_segment(pts[2], segments); 238 add_line_to_segment(pts[2], segments, devBounds);
231 } 239 }
232 } else { 240 } else {
233 segments->push_back(); 241 segments->push_back();
234 segments->back().fType = Segment::kQuad; 242 segments->back().fType = Segment::kQuad;
235 segments->back().fPts[0] = pts[1]; 243 segments->back().fPts[0] = pts[1];
236 segments->back().fPts[1] = pts[2]; 244 segments->back().fPts[1] = pts[2];
245 SkASSERT(contains_inclusive(*devBounds, pts[0]));
246 devBounds->growToInclude(pts + 1, 2);
237 } 247 }
238 } 248 }
239 249
240 static inline void add_cubic_segments(const SkPoint pts[4], 250 static inline void add_cubic_segments(const SkPoint pts[4],
241 SkPath::Direction dir, 251 SkPath::Direction dir,
242 SegmentArray* segments) { 252 SegmentArray* segments,
253 SkRect* devBounds) {
243 SkSTArray<15, SkPoint, true> quads; 254 SkSTArray<15, SkPoint, true> quads;
244 GrPathUtils::convertCubicToQuads(pts, SK_Scalar1, true, dir, &quads); 255 GrPathUtils::convertCubicToQuads(pts, SK_Scalar1, true, dir, &quads);
245 int count = quads.count(); 256 int count = quads.count();
246 for (int q = 0; q < count; q += 3) { 257 for (int q = 0; q < count; q += 3) {
247 add_quad_segment(&quads[q], segments); 258 add_quad_segment(&quads[q], segments, devBounds);
248 } 259 }
249 } 260 }
250 261
251 static bool get_segments(const SkPath& path, 262 static bool get_segments(const SkPath& path,
252 const SkMatrix& m, 263 const SkMatrix& m,
253 SegmentArray* segments, 264 SegmentArray* segments,
254 SkPoint* fanPt, 265 SkPoint* fanPt,
255 int* vCount, 266 int* vCount,
256 int* iCount) { 267 int* iCount,
268 SkRect* devBounds) {
257 SkPath::Iter iter(path, true); 269 SkPath::Iter iter(path, true);
258 // This renderer over-emphasizes very thin path regions. We use the distance 270 // This renderer over-emphasizes very thin path regions. We use the distance
259 // to the path from the sample to compute coverage. Every pixel intersected 271 // to the path from the sample to compute coverage. Every pixel intersected
260 // by the path will be hit and the maximum distance is sqrt(2)/2. We don't 272 // by the path will be hit and the maximum distance is sqrt(2)/2. We don't
261 // notice that the sample may be close to a very thin area of the path and 273 // notice that the sample may be close to a very thin area of the path and
262 // thus should be very light. This is particularly egregious for degenerate 274 // thus should be very light. This is particularly egregious for degenerate
263 // line paths. We detect paths that are very close to a line (zero area) and 275 // line paths. We detect paths that are very close to a line (zero area) and
264 // draw nothing. 276 // draw nothing.
265 DegenerateTestData degenerateData; 277 DegenerateTestData degenerateData;
266 SkPath::Direction dir; 278 SkPath::Direction dir;
267 // get_direction can fail for some degenerate paths. 279 // get_direction can fail for some degenerate paths.
268 if (!get_direction(path, m, &dir)) { 280 if (!get_direction(path, m, &dir)) {
269 return false; 281 return false;
270 } 282 }
271 283
272 for (;;) { 284 for (;;) {
273 GrPoint pts[4]; 285 GrPoint pts[4];
274 SkPath::Verb verb = iter.next(pts); 286 SkPath::Verb verb = iter.next(pts);
275 switch (verb) { 287 switch (verb) {
276 case SkPath::kMove_Verb: 288 case SkPath::kMove_Verb:
277 m.mapPoints(pts, 1); 289 m.mapPoints(pts, 1);
278 update_degenerate_test(&degenerateData, pts[0]); 290 update_degenerate_test(&degenerateData, pts[0]);
291 devBounds->set(pts->fX, pts->fY, pts->fX, pts->fY);
279 break; 292 break;
280 case SkPath::kLine_Verb: { 293 case SkPath::kLine_Verb: {
281 m.mapPoints(&pts[1], 1); 294 m.mapPoints(&pts[1], 1);
282 update_degenerate_test(&degenerateData, pts[1]); 295 update_degenerate_test(&degenerateData, pts[1]);
283 add_line_to_segment(pts[1], segments); 296 add_line_to_segment(pts[1], segments, devBounds);
284 break; 297 break;
285 } 298 }
286 case SkPath::kQuad_Verb: 299 case SkPath::kQuad_Verb:
287 m.mapPoints(pts, 3); 300 m.mapPoints(pts, 3);
288 update_degenerate_test(&degenerateData, pts[1]); 301 update_degenerate_test(&degenerateData, pts[1]);
289 update_degenerate_test(&degenerateData, pts[2]); 302 update_degenerate_test(&degenerateData, pts[2]);
290 add_quad_segment(pts, segments); 303 add_quad_segment(pts, segments, devBounds);
291 break; 304 break;
292 case SkPath::kCubic_Verb: { 305 case SkPath::kCubic_Verb: {
293 m.mapPoints(pts, 4); 306 m.mapPoints(pts, 4);
294 update_degenerate_test(&degenerateData, pts[1]); 307 update_degenerate_test(&degenerateData, pts[1]);
295 update_degenerate_test(&degenerateData, pts[2]); 308 update_degenerate_test(&degenerateData, pts[2]);
296 update_degenerate_test(&degenerateData, pts[3]); 309 update_degenerate_test(&degenerateData, pts[3]);
297 add_cubic_segments(pts, dir, segments); 310 add_cubic_segments(pts, dir, segments, devBounds);
298 break; 311 break;
299 }; 312 };
300 case SkPath::kDone_Verb: 313 case SkPath::kDone_Verb:
301 if (degenerateData.isDegenerate()) { 314 if (degenerateData.isDegenerate()) {
302 return false; 315 return false;
303 } else { 316 } else {
304 compute_vectors(segments, fanPt, dir, vCount, iCount); 317 compute_vectors(segments, fanPt, dir, vCount, iCount);
305 return true; 318 return true;
306 } 319 }
307 default: 320 default:
(...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after
638 651
639 int vCount; 652 int vCount;
640 int iCount; 653 int iCount;
641 enum { 654 enum {
642 kPreallocSegmentCnt = 512 / sizeof(Segment), 655 kPreallocSegmentCnt = 512 / sizeof(Segment),
643 kPreallocDrawCnt = 4, 656 kPreallocDrawCnt = 4,
644 }; 657 };
645 SkSTArray<kPreallocSegmentCnt, Segment, true> segments; 658 SkSTArray<kPreallocSegmentCnt, Segment, true> segments;
646 SkPoint fanPt; 659 SkPoint fanPt;
647 660
648 if (!get_segments(*path, viewMatrix, &segments, &fanPt, &vCount, &iCount)) { 661 // We can't simply use the path bounds because we may degenerate cubics to q uads which produces
662 // new control points outside the original convex hull.
663 SkRect devBounds;
664 if (!get_segments(*path, viewMatrix, &segments, &fanPt, &vCount, &iCount, &d evBounds)) {
649 return false; 665 return false;
650 } 666 }
651 667
668 // Our computed verts should all be within one pixel of the segment control points.
669 devBounds.outset(SK_Scalar1, SK_Scalar1);
670
652 drawState->setVertexAttribs<gPathAttribs>(SK_ARRAY_COUNT(gPathAttribs)); 671 drawState->setVertexAttribs<gPathAttribs>(SK_ARRAY_COUNT(gPathAttribs));
653 672
654 static const int kEdgeAttrIndex = 1; 673 static const int kEdgeAttrIndex = 1;
655 GrEffectRef* quadEffect = QuadEdgeEffect::Create(); 674 GrEffectRef* quadEffect = QuadEdgeEffect::Create();
656 drawState->addCoverageEffect(quadEffect, kEdgeAttrIndex)->unref(); 675 drawState->addCoverageEffect(quadEffect, kEdgeAttrIndex)->unref();
657 676
658 GrDrawTarget::AutoReleaseGeometry arg(target, vCount, iCount); 677 GrDrawTarget::AutoReleaseGeometry arg(target, vCount, iCount);
659 if (!arg.succeeded()) { 678 if (!arg.succeeded()) {
660 return false; 679 return false;
661 } 680 }
662 SkASSERT(sizeof(QuadVertex) == drawState->getVertexSize()); 681 SkASSERT(sizeof(QuadVertex) == drawState->getVertexSize());
663 verts = reinterpret_cast<QuadVertex*>(arg.vertices()); 682 verts = reinterpret_cast<QuadVertex*>(arg.vertices());
664 idxs = reinterpret_cast<uint16_t*>(arg.indices()); 683 idxs = reinterpret_cast<uint16_t*>(arg.indices());
665 684
666 SkSTArray<kPreallocDrawCnt, Draw, true> draws; 685 SkSTArray<kPreallocDrawCnt, Draw, true> draws;
667 create_vertices(segments, fanPt, &draws, verts, idxs); 686 create_vertices(segments, fanPt, &draws, verts, idxs);
668 687
669 // This is valid because all the computed verts are within 1 pixel of the pa th control points.
670 SkRect devBounds;
671 devBounds = path->getBounds();
672 viewMatrix.mapRect(&devBounds);
673 devBounds.outset(SK_Scalar1, SK_Scalar1);
674
675 // Check devBounds 688 // Check devBounds
676 #ifdef SK_DEBUG 689 #ifdef SK_DEBUG
677 SkRect tolDevBounds = devBounds; 690 SkRect tolDevBounds = devBounds;
678 tolDevBounds.outset(SK_Scalar1 / 10000, SK_Scalar1 / 10000); 691 tolDevBounds.outset(SK_Scalar1 / 10000, SK_Scalar1 / 10000);
679 SkRect actualBounds; 692 SkRect actualBounds;
680 actualBounds.set(verts[0].fPos, verts[1].fPos); 693 actualBounds.set(verts[0].fPos, verts[1].fPos);
681 for (int i = 2; i < vCount; ++i) { 694 for (int i = 2; i < vCount; ++i) {
682 actualBounds.growToInclude(verts[i].fPos.fX, verts[i].fPos.fY); 695 actualBounds.growToInclude(verts[i].fPos.fX, verts[i].fPos.fY);
683 } 696 }
684 SkASSERT(tolDevBounds.contains(actualBounds)); 697 SkASSERT(tolDevBounds.contains(actualBounds));
685 #endif 698 #endif
686 699
687 int vOffset = 0; 700 int vOffset = 0;
688 for (int i = 0; i < draws.count(); ++i) { 701 for (int i = 0; i < draws.count(); ++i) {
689 const Draw& draw = draws[i]; 702 const Draw& draw = draws[i];
690 target->drawIndexed(kTriangles_GrPrimitiveType, 703 target->drawIndexed(kTriangles_GrPrimitiveType,
691 vOffset, // start vertex 704 vOffset, // start vertex
692 0, // start index 705 0, // start index
693 draw.fVertexCnt, 706 draw.fVertexCnt,
694 draw.fIndexCnt, 707 draw.fIndexCnt,
695 &devBounds); 708 &devBounds);
696 vOffset += draw.fVertexCnt; 709 vOffset += draw.fVertexCnt;
697 } 710 }
698 711
699 return true; 712 return true;
700 } 713 }
OLDNEW
« 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