Index: src/gpu/GrTessellatingPathRenderer.cpp |
diff --git a/src/gpu/GrTessellatingPathRenderer.cpp b/src/gpu/GrTessellatingPathRenderer.cpp |
index 282efe251666a46ac42b04424e58c76d46c3b447..ee8ee23fa1984806eed06a706778bbc43405c544 100644 |
--- a/src/gpu/GrTessellatingPathRenderer.cpp |
+++ b/src/gpu/GrTessellatingPathRenderer.cpp |
@@ -1384,9 +1384,11 @@ private: |
} // namespace |
bool GrTessellatingPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { |
- // This path renderer can draw all fill styles, but does not do antialiasing. It can do convex |
- // and concave paths, but we'll leave the convex ones to simpler algorithms. |
- return args.fStroke->isFillStyle() && !args.fAntiAlias && !args.fPath->isConvex(); |
+ // This path renderer can draw all fill styles, all stroke styles except hairlines, but does |
+ // not do antialiasing. It can do convex and concave paths, but we'll leave the convex ones to |
+ // simpler algorithms. |
+ return !IsStrokeHairlineOrEquivalent(*args.fStroke, *args.fViewMatrix, NULL) && |
+ !args.fAntiAlias && !args.fPath->isConvex(); |
} |
class TessellatingPathBatch : public GrBatch { |
@@ -1394,9 +1396,10 @@ public: |
static GrBatch* Create(const GrColor& color, |
const SkPath& path, |
+ const GrStrokeInfo& stroke, |
const SkMatrix& viewMatrix, |
SkRect clipBounds) { |
- return SkNEW_ARGS(TessellatingPathBatch, (color, path, viewMatrix, clipBounds)); |
+ return SkNEW_ARGS(TessellatingPathBatch, (color, path, stroke, viewMatrix, clipBounds)); |
} |
const char* name() const override { return "TessellatingPathBatch"; } |
@@ -1421,7 +1424,23 @@ public: |
int tessellate(GrUniqueKey* key, |
GrResourceProvider* resourceProvider, |
SkAutoTUnref<GrVertexBuffer>& vertexBuffer) { |
- SkRect pathBounds = fPath.getBounds(); |
+ SkPath path; |
+ GrStrokeInfo stroke(fStroke); |
+ if (stroke.isDashed()) { |
+ if (!stroke.applyDashToPath(&path, &stroke, fPath)) { |
+ return 0; |
+ } |
+ } else { |
+ path = fPath; |
+ } |
+ if (!stroke.isFillStyle()) { |
+ stroke.setResScale(SkScalarAbs(fViewMatrix.getMaxScale())); |
+ if (!stroke.applyToPath(&path, path)) { |
+ return 0; |
+ } |
+ stroke.setFillStyle(); |
+ } |
+ SkRect pathBounds = path.getBounds(); |
Comparator c; |
if (pathBounds.width() > pathBounds.height()) { |
c.sweep_lt = sweep_lt_horiz; |
@@ -1433,7 +1452,7 @@ public: |
SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance; |
SkScalar tol = GrPathUtils::scaleToleranceToSrc(screenSpaceTol, fViewMatrix, pathBounds); |
int contourCnt; |
- int maxPts = GrPathUtils::worstCasePointCount(fPath, &contourCnt, tol); |
+ int maxPts = GrPathUtils::worstCasePointCount(path, &contourCnt, tol); |
if (maxPts <= 0) { |
return 0; |
} |
@@ -1441,7 +1460,7 @@ public: |
SkDebugf("Path not rendered, too many verts (%d)\n", maxPts); |
return 0; |
} |
- SkPath::FillType fillType = fPath.getFillType(); |
+ SkPath::FillType fillType = path.getFillType(); |
if (SkPath::IsInverseFillType(fillType)) { |
contourCnt++; |
} |
@@ -1455,7 +1474,7 @@ public: |
// connectivity of one Edge per Vertex (will grow for intersections). |
SkChunkAlloc alloc(maxPts * (3 * sizeof(Vertex) + sizeof(Edge))); |
bool isLinear; |
- path_to_contours(fPath, tol, fClipBounds, contours.get(), alloc, &isLinear); |
+ path_to_contours(path, tol, fClipBounds, contours.get(), alloc, &isLinear); |
Poly* polys; |
polys = contours_to_polys(contours.get(), contourCnt, c, alloc); |
int count = 0; |
@@ -1503,13 +1522,15 @@ public: |
GrUniqueKey key; |
int clipBoundsSize32 = |
fPath.isInverseFillType() ? sizeof(fClipBounds) / sizeof(uint32_t) : 0; |
- GrUniqueKey::Builder builder(&key, kDomain, 2 + clipBoundsSize32); |
+ int strokeDataSize32 = fStroke.computeUniqueKeyFragmentData32Cnt(); |
+ GrUniqueKey::Builder builder(&key, kDomain, 2 + clipBoundsSize32 + strokeDataSize32); |
builder[0] = fPath.getGenerationID(); |
builder[1] = fPath.getFillType(); |
// For inverse fills, the tessellation is dependent on clip bounds. |
if (fPath.isInverseFillType()) { |
memcpy(&builder[2], &fClipBounds, sizeof(fClipBounds)); |
} |
+ fStroke.asUniqueKeyFragment(&builder[2 + clipBoundsSize32]); |
builder.finish(); |
GrResourceProvider* rp = batchTarget->resourceProvider(); |
SkAutoTUnref<GrVertexBuffer> vertexBuffer(rp->findAndRefTByUniqueKey<GrVertexBuffer>(key)); |
@@ -1561,20 +1582,33 @@ public: |
private: |
TessellatingPathBatch(const GrColor& color, |
const SkPath& path, |
+ const GrStrokeInfo& stroke, |
const SkMatrix& viewMatrix, |
const SkRect& clipBounds) |
: fColor(color) |
, fPath(path) |
+ , fStroke(stroke) |
, fViewMatrix(viewMatrix) |
, fClipBounds(clipBounds) { |
this->initClassID<TessellatingPathBatch>(); |
fBounds = path.getBounds(); |
+ if (!stroke.isFillStyle()) { |
+ SkScalar radius = SkScalarHalf(stroke.getWidth()); |
+ if (stroke.getJoin() == SkPaint::kMiter_Join) { |
+ SkScalar scale = stroke.getMiter(); |
+ if (scale > SK_Scalar1) { |
+ radius = SkScalarMul(radius, scale); |
+ } |
+ } |
+ fBounds.outset(radius, radius); |
+ } |
viewMatrix.mapRect(&fBounds); |
} |
GrColor fColor; |
SkPath fPath; |
+ GrStrokeInfo fStroke; |
SkMatrix fViewMatrix; |
SkRect fClipBounds; // in source space |
GrPipelineInfo fPipelineInfo; |
@@ -1596,7 +1630,8 @@ bool GrTessellatingPathRenderer::onDrawPath(const DrawPathArgs& args) { |
} |
vmi.mapRect(&clipBounds); |
SkAutoTUnref<GrBatch> batch(TessellatingPathBatch::Create(args.fColor, *args.fPath, |
- *args.fViewMatrix, clipBounds)); |
+ *args.fStroke, *args.fViewMatrix, |
+ clipBounds)); |
args.fTarget->drawBatch(*args.fPipelineBuilder, batch); |
return true; |
@@ -1617,7 +1652,8 @@ BATCH_TEST_DEFINE(TesselatingPathBatch) { |
SkFAIL("Cannot invert matrix\n"); |
} |
vmi.mapRect(&clipBounds); |
- return TessellatingPathBatch::Create(color, path, viewMatrix, clipBounds); |
+ GrStrokeInfo strokeInfo = GrTest::TestStrokeInfo(random); |
+ return TessellatingPathBatch::Create(color, path, strokeInfo, viewMatrix, clipBounds); |
} |
#endif |