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 |