| OLD | NEW |
| 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 Loading... |
| 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(°enerateData, pts[0]); | 290 update_degenerate_test(°enerateData, 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(°enerateData, pts[1]); | 295 update_degenerate_test(°enerateData, 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(°enerateData, pts[1]); | 301 update_degenerate_test(°enerateData, pts[1]); |
| 289 update_degenerate_test(°enerateData, pts[2]); | 302 update_degenerate_test(°enerateData, 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(°enerateData, pts[1]); | 307 update_degenerate_test(°enerateData, pts[1]); |
| 295 update_degenerate_test(°enerateData, pts[2]); | 308 update_degenerate_test(°enerateData, pts[2]); |
| 296 update_degenerate_test(°enerateData, pts[3]); | 309 update_degenerate_test(°enerateData, 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 Loading... |
| 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 } |
| OLD | NEW |