Index: src/gpu/batches/GrAAConvexTessellator.cpp |
diff --git a/src/gpu/batches/GrAAConvexTessellator.cpp b/src/gpu/batches/GrAAConvexTessellator.cpp |
index af3ce89257d890132db64b5767bf120fd3b5540c..2fc33a835790e41b5e53dbaed46c5ec3556f0380 100644 |
--- a/src/gpu/batches/GrAAConvexTessellator.cpp |
+++ b/src/gpu/batches/GrAAConvexTessellator.cpp |
@@ -32,11 +32,17 @@ static const SkScalar kRoundCapThreshold = 0.8f; |
// dot product above which we consider two adjacent curves to be part of the "same" curve |
static const SkScalar kCurveConnectionThreshold = 0.8f; |
-static SkScalar intersect(const SkPoint& p0, const SkPoint& n0, |
- const SkPoint& p1, const SkPoint& n1) { |
+static bool intersect(const SkPoint& p0, const SkPoint& n0, |
+ const SkPoint& p1, const SkPoint& n1, |
+ SkScalar* t) { |
const SkPoint v = p1 - p0; |
SkScalar perpDot = n0.fX * n1.fY - n0.fY * n1.fX; |
- return (v.fX * n1.fY - v.fY * n1.fX) / perpDot; |
+ if (SkScalarNearlyZero(perpDot)) { |
+ return false; |
+ } |
+ *t = (v.fX * n1.fY - v.fY * n1.fX) / perpDot; |
+ SkASSERT(SkScalarIsFinite(*t)); |
+ return true; |
} |
// This is a special case version of intersect where we have the vector |
@@ -218,7 +224,45 @@ bool GrAAConvexTessellator::tessellate(const SkMatrix& m, const SkPath& path) { |
SkScalar coverage = 1.0f; |
SkScalar scaleFactor = 0.0f; |
- if (fStrokeWidth >= 0.0f) { |
+ |
+ if (SkStrokeRec::kStrokeAndFill_Style == fStyle) { |
+ SkASSERT(m.isSimilarity()); |
+ scaleFactor = m.getMaxScale(); // x and y scale are the same |
+ SkScalar effectiveStrokeWidth = scaleFactor * fStrokeWidth; |
+ Ring outerStrokeAndAARing; |
+ this->createOuterRing(fInitialRing, |
+ effectiveStrokeWidth / 2 + kAntialiasingRadius, 0.0, |
+ &outerStrokeAndAARing); |
+ |
+ // discard all the triangles added between the originating ring and the new outer ring |
+ fIndices.rewind(); |
+ |
+ outerStrokeAndAARing.init(*this); |
+ |
+ outerStrokeAndAARing.makeOriginalRing(); |
+ |
+ // Add the outer stroke ring's normals to the originating ring's normals |
+ // so it can also act as an originating ring |
+ fNorms.setCount(fNorms.count() + outerStrokeAndAARing.numPts()); |
+ for (int i = 0; i < outerStrokeAndAARing.numPts(); ++i) { |
+ SkASSERT(outerStrokeAndAARing.index(i) < fNorms.count()); |
+ fNorms[outerStrokeAndAARing.index(i)] = outerStrokeAndAARing.norm(i); |
+ } |
+ |
+ // the bisectors are only needed for the computation of the outer ring |
+ fBisectors.rewind(); |
+ |
+ Ring* insetAARing; |
+ this->createInsetRings(outerStrokeAndAARing, |
+ 0.0f, 0.0f, 2*kAntialiasingRadius, 1.0f, |
+ &insetAARing); |
+ |
+ SkDEBUGCODE(this->validate();) |
+ return true; |
+ } |
+ |
+ if (SkStrokeRec::kStroke_Style == fStyle) { |
+ SkASSERT(fStrokeWidth >= 0.0f); |
SkASSERT(m.isSimilarity()); |
scaleFactor = m.getMaxScale(); // x and y scale are the same |
SkScalar effectiveStrokeWidth = scaleFactor * fStrokeWidth; |
@@ -235,15 +279,16 @@ bool GrAAConvexTessellator::tessellate(const SkMatrix& m, const SkPath& path) { |
// the bisectors are only needed for the computation of the outer ring |
fBisectors.rewind(); |
- if (fStrokeWidth >= 0.0f && fInitialRing.numPts() > 2) { |
+ if (SkStrokeRec::kStroke_Style == fStyle && fInitialRing.numPts() > 2) { |
+ SkASSERT(fStrokeWidth >= 0.0f); |
SkScalar effectiveStrokeWidth = scaleFactor * fStrokeWidth; |
Ring* insetStrokeRing; |
SkScalar strokeDepth = effectiveStrokeWidth / 2 - kAntialiasingRadius; |
if (this->createInsetRings(fInitialRing, 0.0f, coverage, strokeDepth, coverage, |
- &insetStrokeRing)) { |
+ &insetStrokeRing)) { |
Ring* insetAARing; |
this->createInsetRings(*insetStrokeRing, strokeDepth, coverage, strokeDepth + |
- kAntialiasingRadius * 2, 0.0f, &insetAARing); |
+ kAntialiasingRadius * 2, 0.0f, &insetAARing); |
} |
} else { |
Ring* insetAARing; |
@@ -390,7 +435,7 @@ bool GrAAConvexTessellator::extractFromPath(const SkMatrix& m, const SkPath& pat |
this->computeBisectors(); |
} else if (this->numPts() == 2) { |
// We've got two points, so we're degenerate. |
- if (fStrokeWidth < 0.0f) { |
+ if (fStyle == SkStrokeRec::kFill_Style) { |
// it's a fill, so we don't need to worry about degenerate paths |
return false; |
} |
@@ -586,7 +631,7 @@ void GrAAConvexTessellator::createOuterRing(const Ring& previousRing, SkScalar o |
// Something went wrong in the creation of the next ring. If we're filling the shape, just go ahead |
// and fan it. |
void GrAAConvexTessellator::terminate(const Ring& ring) { |
- if (fStrokeWidth < 0.0f) { |
+ if (fStyle != SkStrokeRec::kStroke_Style) { |
this->fanRing(ring); |
} |
} |
@@ -616,8 +661,14 @@ bool GrAAConvexTessellator::createInsetRing(const Ring& lastRing, Ring* nextRing |
for (int cur = 0; cur < lastRing.numPts(); ++cur) { |
int next = (cur + 1) % lastRing.numPts(); |
- SkScalar t = intersect(this->point(lastRing.index(cur)), lastRing.bisector(cur), |
- this->point(lastRing.index(next)), lastRing.bisector(next)); |
+ |
+ SkScalar t; |
+ bool result = intersect(this->point(lastRing.index(cur)), lastRing.bisector(cur), |
+ this->point(lastRing.index(next)), lastRing.bisector(next), |
+ &t); |
+ if (!result) { |
+ continue; |
+ } |
SkScalar dist = -t * lastRing.norm(cur).dot(lastRing.bisector(cur)); |
if (minDist > dist) { |
@@ -745,8 +796,8 @@ bool GrAAConvexTessellator::createInsetRing(const Ring& lastRing, Ring* nextRing |
this->addTri(lastRing.index(i), dst[next], dst[i]); |
} |
- if (done && fStrokeWidth < 0.0f) { |
- // fill |
+ if (done && fStyle != SkStrokeRec::kStroke_Style) { |
+ // fill or stroke-and-fill |
this->fanRing(*nextRing); |
} |
@@ -860,7 +911,7 @@ void GrAAConvexTessellator::lineTo(SkPoint p, CurveState curve) { |
return; |
} |
} |
- SkScalar initialRingCoverage = fStrokeWidth < 0.0f ? 0.5f : 1.0f; |
+ SkScalar initialRingCoverage = (SkStrokeRec::kFill_Style == fStyle) ? 0.5f : 1.0f; |
this->addPt(p, 0.0f, initialRingCoverage, false, curve); |
if (this->numPts() > 1) { |
*fNorms.push() = fPts.top() - fPts[fPts.count()-2]; |