1 /*
2  * Copyright 2011 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "GrDefaultPathRenderer.h"
9 
10 #include "GrBatchFlushState.h"
11 #include "GrBatchTest.h"
12 #include "GrContext.h"
13 #include "GrDefaultGeoProcFactory.h"
14 #include "GrPathUtils.h"
15 #include "GrPipelineBuilder.h"
16 #include "GrVertices.h"
17 #include "SkGeometry.h"
18 #include "SkString.h"
19 #include "SkStrokeRec.h"
20 #include "SkTLazy.h"
21 #include "SkTraceEvent.h"
22 
23 #include "batches/GrRectBatchFactory.h"
24 #include "batches/GrVertexBatch.h"
25 
GrDefaultPathRenderer(bool separateStencilSupport,bool stencilWrapOpsSupport)26 GrDefaultPathRenderer::GrDefaultPathRenderer(bool separateStencilSupport,
27                                              bool stencilWrapOpsSupport)
28     : fSeparateStencil(separateStencilSupport)
29     , fStencilWrapOps(stencilWrapOpsSupport) {
30 }
31 
32 
33 ////////////////////////////////////////////////////////////////////////////////
34 // Stencil rules for paths
35 
36 ////// Even/Odd
37 
38 GR_STATIC_CONST_SAME_STENCIL(gEOStencilPass,
39     kInvert_StencilOp,
40     kKeep_StencilOp,
41     kAlwaysIfInClip_StencilFunc,
42     0xffff,
43     0xffff,
44     0xffff);
45 
46 // ok not to check clip b/c stencil pass only wrote inside clip
47 GR_STATIC_CONST_SAME_STENCIL(gEOColorPass,
48     kZero_StencilOp,
49     kZero_StencilOp,
50     kNotEqual_StencilFunc,
51     0xffff,
52     0x0000,
53     0xffff);
54 
55 // have to check clip b/c outside clip will always be zero.
56 GR_STATIC_CONST_SAME_STENCIL(gInvEOColorPass,
57     kZero_StencilOp,
58     kZero_StencilOp,
59     kEqualIfInClip_StencilFunc,
60     0xffff,
61     0x0000,
62     0xffff);
63 
64 ////// Winding
65 
66 // when we have separate stencil we increment front faces / decrement back faces
67 // when we don't have wrap incr and decr we use the stencil test to simulate
68 // them.
69 
70 GR_STATIC_CONST_STENCIL(gWindStencilSeparateWithWrap,
71     kIncWrap_StencilOp,             kDecWrap_StencilOp,
72     kKeep_StencilOp,                kKeep_StencilOp,
73     kAlwaysIfInClip_StencilFunc,    kAlwaysIfInClip_StencilFunc,
74     0xffff,                         0xffff,
75     0xffff,                         0xffff,
76     0xffff,                         0xffff);
77 
78 // if inc'ing the max value, invert to make 0
79 // if dec'ing zero invert to make all ones.
80 // we can't avoid touching the stencil on both passing and
81 // failing, so we can't resctrict ourselves to the clip.
82 GR_STATIC_CONST_STENCIL(gWindStencilSeparateNoWrap,
83     kInvert_StencilOp,              kInvert_StencilOp,
84     kIncClamp_StencilOp,            kDecClamp_StencilOp,
85     kEqual_StencilFunc,             kEqual_StencilFunc,
86     0xffff,                         0xffff,
87     0xffff,                         0x0000,
88     0xffff,                         0xffff);
89 
90 // When there are no separate faces we do two passes to setup the winding rule
91 // stencil. First we draw the front faces and inc, then we draw the back faces
92 // and dec. These are same as the above two split into the incrementing and
93 // decrementing passes.
94 GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilWithWrapInc,
95     kIncWrap_StencilOp,
96     kKeep_StencilOp,
97     kAlwaysIfInClip_StencilFunc,
98     0xffff,
99     0xffff,
100     0xffff);
101 
102 GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilWithWrapDec,
103     kDecWrap_StencilOp,
104     kKeep_StencilOp,
105     kAlwaysIfInClip_StencilFunc,
106     0xffff,
107     0xffff,
108     0xffff);
109 
110 GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilNoWrapInc,
111     kInvert_StencilOp,
112     kIncClamp_StencilOp,
113     kEqual_StencilFunc,
114     0xffff,
115     0xffff,
116     0xffff);
117 
118 GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilNoWrapDec,
119     kInvert_StencilOp,
120     kDecClamp_StencilOp,
121     kEqual_StencilFunc,
122     0xffff,
123     0x0000,
124     0xffff);
125 
126 // Color passes are the same whether we use the two-sided stencil or two passes
127 
128 GR_STATIC_CONST_SAME_STENCIL(gWindColorPass,
129     kZero_StencilOp,
130     kZero_StencilOp,
131     kNonZeroIfInClip_StencilFunc,
132     0xffff,
133     0x0000,
134     0xffff);
135 
136 GR_STATIC_CONST_SAME_STENCIL(gInvWindColorPass,
137     kZero_StencilOp,
138     kZero_StencilOp,
139     kEqualIfInClip_StencilFunc,
140     0xffff,
141     0x0000,
142     0xffff);
143 
144 ////// Normal render to stencil
145 
146 // Sometimes the default path renderer can draw a path directly to the stencil
147 // buffer without having to first resolve the interior / exterior.
148 GR_STATIC_CONST_SAME_STENCIL(gDirectToStencil,
149     kZero_StencilOp,
150     kIncClamp_StencilOp,
151     kAlwaysIfInClip_StencilFunc,
152     0xffff,
153     0x0000,
154     0xffff);
155 
156 ////////////////////////////////////////////////////////////////////////////////
157 // Helpers for drawPath
158 
159 #define STENCIL_OFF     0   // Always disable stencil (even when needed)
160 
single_pass_path(const SkPath & path,const SkStrokeRec & stroke)161 static inline bool single_pass_path(const SkPath& path, const SkStrokeRec& stroke) {
162 #if STENCIL_OFF
163     return true;
164 #else
165     if (!stroke.isHairlineStyle() && !path.isInverseFillType()) {
166         return path.isConvex();
167     }
168     return false;
169 #endif
170 }
171 
172 GrPathRenderer::StencilSupport
onGetStencilSupport(const SkPath & path,const GrStrokeInfo & stroke) const173 GrDefaultPathRenderer::onGetStencilSupport(const SkPath& path, const GrStrokeInfo& stroke) const {
174     if (single_pass_path(path, stroke)) {
175         return GrPathRenderer::kNoRestriction_StencilSupport;
176     } else {
177         return GrPathRenderer::kStencilOnly_StencilSupport;
178     }
179 }
180 
append_countour_edge_indices(bool hairLine,uint16_t fanCenterIdx,uint16_t edgeV0Idx,uint16_t ** indices)181 static inline void append_countour_edge_indices(bool hairLine,
182                                                 uint16_t fanCenterIdx,
183                                                 uint16_t edgeV0Idx,
184                                                 uint16_t** indices) {
185     // when drawing lines we're appending line segments along
186     // the contour. When applying the other fill rules we're
187     // drawing triangle fans around fanCenterIdx.
188     if (!hairLine) {
189         *((*indices)++) = fanCenterIdx;
190     }
191     *((*indices)++) = edgeV0Idx;
192     *((*indices)++) = edgeV0Idx + 1;
193 }
194 
add_quad(SkPoint ** vert,const SkPoint * base,const SkPoint pts[],SkScalar srcSpaceTolSqd,SkScalar srcSpaceTol,bool indexed,bool isHairline,uint16_t subpathIdxStart,int offset,uint16_t ** idx)195 static inline void add_quad(SkPoint** vert, const SkPoint* base, const SkPoint pts[],
196                             SkScalar srcSpaceTolSqd, SkScalar srcSpaceTol, bool indexed,
197                             bool isHairline, uint16_t subpathIdxStart, int offset, uint16_t** idx) {
198     // first pt of quad is the pt we ended on in previous step
199     uint16_t firstQPtIdx = (uint16_t)(*vert - base) - 1 + offset;
200     uint16_t numPts =  (uint16_t)
201         GrPathUtils::generateQuadraticPoints(
202             pts[0], pts[1], pts[2],
203             srcSpaceTolSqd, vert,
204             GrPathUtils::quadraticPointCount(pts, srcSpaceTol));
205     if (indexed) {
206         for (uint16_t i = 0; i < numPts; ++i) {
207             append_countour_edge_indices(isHairline, subpathIdxStart,
208                                          firstQPtIdx + i, idx);
209         }
210     }
211 }
212 
213 class DefaultPathBatch : public GrVertexBatch {
214 public:
215     DEFINE_BATCH_CLASS_ID
216 
217     struct Geometry {
218         GrColor fColor;
219         SkPath fPath;
220         SkScalar fTolerance;
221     };
222 
Create(const Geometry & geometry,uint8_t coverage,const SkMatrix & viewMatrix,bool isHairline,const SkRect & devBounds)223     static GrDrawBatch* Create(const Geometry& geometry, uint8_t coverage,
224                                const SkMatrix& viewMatrix, bool isHairline,
225                                const SkRect& devBounds) {
226         return new DefaultPathBatch(geometry, coverage, viewMatrix, isHairline, devBounds);
227     }
228 
name() const229     const char* name() const override { return "DefaultPathBatch"; }
230 
computePipelineOptimizations(GrInitInvariantOutput * color,GrInitInvariantOutput * coverage,GrBatchToXPOverrides * overrides) const231     void computePipelineOptimizations(GrInitInvariantOutput* color,
232                                       GrInitInvariantOutput* coverage,
233                                       GrBatchToXPOverrides* overrides) const override {
234         // When this is called on a batch, there is only one geometry bundle
235         color->setKnownFourComponents(fGeoData[0].fColor);
236         coverage->setKnownSingleComponent(this->coverage());
237     }
238 
239 private:
initBatchTracker(const GrXPOverridesForBatch & overrides)240     void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
241         // Handle any color overrides
242         if (!overrides.readsColor()) {
243             fGeoData[0].fColor = GrColor_ILLEGAL;
244         }
245         overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
246 
247         // setup batch properties
248         fBatch.fColorIgnored = !overrides.readsColor();
249         fBatch.fColor = fGeoData[0].fColor;
250         fBatch.fUsesLocalCoords = overrides.readsLocalCoords();
251         fBatch.fCoverageIgnored = !overrides.readsCoverage();
252     }
253 
onPrepareDraws(Target * target) const254     void onPrepareDraws(Target* target) const override {
255         SkAutoTUnref<const GrGeometryProcessor> gp;
256         {
257             using namespace GrDefaultGeoProcFactory;
258             Color color(this->color());
259             Coverage coverage(this->coverage());
260             if (this->coverageIgnored()) {
261                 coverage.fType = Coverage::kNone_Type;
262             }
263             LocalCoords localCoords(this->usesLocalCoords() ? LocalCoords::kUsePosition_Type :
264                                                               LocalCoords::kUnused_Type);
265             gp.reset(GrDefaultGeoProcFactory::Create(color, coverage, localCoords,
266                                                      this->viewMatrix()));
267         }
268 
269         size_t vertexStride = gp->getVertexStride();
270         SkASSERT(vertexStride == sizeof(SkPoint));
271 
272         target->initDraw(gp, this->pipeline());
273 
274         int instanceCount = fGeoData.count();
275 
276         // compute number of vertices
277         int maxVertices = 0;
278 
279         // We will use index buffers if we have multiple paths or one path with multiple contours
280         bool isIndexed = instanceCount > 1;
281         for (int i = 0; i < instanceCount; i++) {
282             const Geometry& args = fGeoData[i];
283 
284             int contourCount;
285             maxVertices += GrPathUtils::worstCasePointCount(args.fPath, &contourCount,
286                                                             args.fTolerance);
287 
288             isIndexed = isIndexed || contourCount > 1;
289         }
290 
291         if (maxVertices == 0 || maxVertices > ((int)SK_MaxU16 + 1)) {
292             //SkDebugf("Cannot render path (%d)\n", maxVertices);
293             return;
294         }
295 
296         // determine primitiveType
297         int maxIndices = 0;
298         GrPrimitiveType primitiveType;
299         if (this->isHairline()) {
300             if (isIndexed) {
301                 maxIndices = 2 * maxVertices;
302                 primitiveType = kLines_GrPrimitiveType;
303             } else {
304                 primitiveType = kLineStrip_GrPrimitiveType;
305             }
306         } else {
307             if (isIndexed) {
308                 maxIndices = 3 * maxVertices;
309                 primitiveType = kTriangles_GrPrimitiveType;
310             } else {
311                 primitiveType = kTriangleFan_GrPrimitiveType;
312             }
313         }
314 
315         // allocate vertex / index buffers
316         const GrVertexBuffer* vertexBuffer;
317         int firstVertex;
318 
319         void* verts = target->makeVertexSpace(vertexStride, maxVertices,
320                                               &vertexBuffer, &firstVertex);
321 
322         if (!verts) {
323             SkDebugf("Could not allocate vertices\n");
324             return;
325         }
326 
327         const GrIndexBuffer* indexBuffer = nullptr;
328         int firstIndex = 0;
329 
330         void* indices = nullptr;
331         if (isIndexed) {
332             indices = target->makeIndexSpace(maxIndices, &indexBuffer, &firstIndex);
333 
334             if (!indices) {
335                 SkDebugf("Could not allocate indices\n");
336                 return;
337             }
338         }
339 
340         // fill buffers
341         int vertexOffset = 0;
342         int indexOffset = 0;
343         for (int i = 0; i < instanceCount; i++) {
344             const Geometry& args = fGeoData[i];
345 
346             int vertexCnt = 0;
347             int indexCnt = 0;
348             if (!this->createGeom(verts,
349                                   vertexOffset,
350                                   indices,
351                                   indexOffset,
352                                   &vertexCnt,
353                                   &indexCnt,
354                                   args.fPath,
355                                   args.fTolerance,
356                                   isIndexed)) {
357                 return;
358             }
359 
360             vertexOffset += vertexCnt;
361             indexOffset += indexCnt;
362             SkASSERT(vertexOffset <= maxVertices && indexOffset <= maxIndices);
363         }
364 
365         GrVertices vertices;
366         if (isIndexed) {
367             vertices.initIndexed(primitiveType, vertexBuffer, indexBuffer, firstVertex, firstIndex,
368                                  vertexOffset, indexOffset);
369         } else {
370             vertices.init(primitiveType, vertexBuffer, firstVertex, vertexOffset);
371         }
372         target->draw(vertices);
373 
374         // put back reserves
375         target->putBackIndices((size_t)(maxIndices - indexOffset));
376         target->putBackVertices((size_t)(maxVertices - vertexOffset), (size_t)vertexStride);
377     }
378 
geoData()379     SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
380 
DefaultPathBatch(const Geometry & geometry,uint8_t coverage,const SkMatrix & viewMatrix,bool isHairline,const SkRect & devBounds)381     DefaultPathBatch(const Geometry& geometry, uint8_t coverage, const SkMatrix& viewMatrix,
382                      bool isHairline, const SkRect& devBounds)
383         : INHERITED(ClassID()) {
384         fBatch.fCoverage = coverage;
385         fBatch.fIsHairline = isHairline;
386         fBatch.fViewMatrix = viewMatrix;
387         fGeoData.push_back(geometry);
388 
389         this->setBounds(devBounds);
390 
391         // This is b.c. hairlines are notionally infinitely thin so without expansion
392         // two overlapping lines could be reordered even though they hit the same pixels.
393         if (isHairline) {
394             fBounds.outset(0.5f, 0.5f);
395         }
396     }
397 
onCombineIfPossible(GrBatch * t,const GrCaps & caps)398     bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
399         DefaultPathBatch* that = t->cast<DefaultPathBatch>();
400         if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
401                                      that->bounds(), caps)) {
402             return false;
403         }
404 
405         if (this->color() != that->color()) {
406             return false;
407         }
408 
409         if (this->coverage() != that->coverage()) {
410             return false;
411         }
412 
413         if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
414             return false;
415         }
416 
417         if (this->isHairline() != that->isHairline()) {
418             return false;
419         }
420 
421         fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
422         this->joinBounds(that->bounds());
423         return true;
424     }
425 
createGeom(void * vertices,size_t vertexOffset,void * indices,size_t indexOffset,int * vertexCnt,int * indexCnt,const SkPath & path,SkScalar srcSpaceTol,bool isIndexed) const426     bool createGeom(void* vertices,
427                     size_t vertexOffset,
428                     void* indices,
429                     size_t indexOffset,
430                     int* vertexCnt,
431                     int* indexCnt,
432                     const SkPath& path,
433                     SkScalar srcSpaceTol,
434                     bool isIndexed) const {
435         {
436             SkScalar srcSpaceTolSqd = SkScalarMul(srcSpaceTol, srcSpaceTol);
437 
438             uint16_t indexOffsetU16 = (uint16_t)indexOffset;
439             uint16_t vertexOffsetU16 = (uint16_t)vertexOffset;
440 
441             uint16_t* idxBase = reinterpret_cast<uint16_t*>(indices) + indexOffsetU16;
442             uint16_t* idx = idxBase;
443             uint16_t subpathIdxStart = vertexOffsetU16;
444 
445             SkPoint* base = reinterpret_cast<SkPoint*>(vertices) + vertexOffset;
446             SkPoint* vert = base;
447 
448             SkPoint pts[4];
449 
450             bool first = true;
451             int subpath = 0;
452 
453             SkPath::Iter iter(path, false);
454 
455             bool done = false;
456             while (!done) {
457                 SkPath::Verb verb = iter.next(pts);
458                 switch (verb) {
459                     case SkPath::kMove_Verb:
460                         if (!first) {
461                             uint16_t currIdx = (uint16_t) (vert - base) + vertexOffsetU16;
462                             subpathIdxStart = currIdx;
463                             ++subpath;
464                         }
465                         *vert = pts[0];
466                         vert++;
467                         break;
468                     case SkPath::kLine_Verb:
469                         if (isIndexed) {
470                             uint16_t prevIdx = (uint16_t)(vert - base) - 1 + vertexOffsetU16;
471                             append_countour_edge_indices(this->isHairline(), subpathIdxStart,
472                                                          prevIdx, &idx);
473                         }
474                         *(vert++) = pts[1];
475                         break;
476                     case SkPath::kConic_Verb: {
477                         SkScalar weight = iter.conicWeight();
478                         SkAutoConicToQuads converter;
479                         // Converting in src-space, hance the finer tolerance (0.25)
480                         // TODO: find a way to do this in dev-space so the tolerance means something
481                         const SkPoint* quadPts = converter.computeQuads(pts, weight, 0.25f);
482                         for (int i = 0; i < converter.countQuads(); ++i) {
483                             add_quad(&vert, base, quadPts + i*2, srcSpaceTolSqd, srcSpaceTol,
484                                      isIndexed, this->isHairline(), subpathIdxStart,
485                                      (int)vertexOffset, &idx);
486                         }
487                         break;
488                     }
489                     case SkPath::kQuad_Verb:
490                         add_quad(&vert, base, pts, srcSpaceTolSqd, srcSpaceTol, isIndexed,
491                                  this->isHairline(), subpathIdxStart, (int)vertexOffset, &idx);
492                         break;
493                     case SkPath::kCubic_Verb: {
494                         // first pt of cubic is the pt we ended on in previous step
495                         uint16_t firstCPtIdx = (uint16_t)(vert - base) - 1 + vertexOffsetU16;
496                         uint16_t numPts = (uint16_t) GrPathUtils::generateCubicPoints(
497                                         pts[0], pts[1], pts[2], pts[3],
498                                         srcSpaceTolSqd, &vert,
499                                         GrPathUtils::cubicPointCount(pts, srcSpaceTol));
500                         if (isIndexed) {
501                             for (uint16_t i = 0; i < numPts; ++i) {
502                                 append_countour_edge_indices(this->isHairline(), subpathIdxStart,
503                                                              firstCPtIdx + i, &idx);
504                             }
505                         }
506                         break;
507                     }
508                     case SkPath::kClose_Verb:
509                         break;
510                     case SkPath::kDone_Verb:
511                         done = true;
512                 }
513                 first = false;
514             }
515 
516             *vertexCnt = static_cast<int>(vert - base);
517             *indexCnt = static_cast<int>(idx - idxBase);
518 
519         }
520         return true;
521     }
522 
color() const523     GrColor color() const { return fBatch.fColor; }
coverage() const524     uint8_t coverage() const { return fBatch.fCoverage; }
usesLocalCoords() const525     bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
viewMatrix() const526     const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; }
isHairline() const527     bool isHairline() const { return fBatch.fIsHairline; }
coverageIgnored() const528     bool coverageIgnored() const { return fBatch.fCoverageIgnored; }
529 
530     struct BatchTracker {
531         GrColor fColor;
532         uint8_t fCoverage;
533         SkMatrix fViewMatrix;
534         bool fUsesLocalCoords;
535         bool fColorIgnored;
536         bool fCoverageIgnored;
537         bool fIsHairline;
538     };
539 
540     BatchTracker fBatch;
541     SkSTArray<1, Geometry, true> fGeoData;
542 
543     typedef GrVertexBatch INHERITED;
544 };
545 
internalDrawPath(GrDrawTarget * target,GrPipelineBuilder * pipelineBuilder,GrColor color,const SkMatrix & viewMatrix,const SkPath & path,const GrStrokeInfo & origStroke,bool stencilOnly)546 bool GrDefaultPathRenderer::internalDrawPath(GrDrawTarget* target,
547                                              GrPipelineBuilder* pipelineBuilder,
548                                              GrColor color,
549                                              const SkMatrix& viewMatrix,
550                                              const SkPath& path,
551                                              const GrStrokeInfo& origStroke,
552                                              bool stencilOnly) {
553     SkTCopyOnFirstWrite<GrStrokeInfo> stroke(origStroke);
554 
555     SkScalar hairlineCoverage;
556     uint8_t newCoverage = 0xff;
557     if (IsStrokeHairlineOrEquivalent(*stroke, viewMatrix, &hairlineCoverage)) {
558         newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff);
559 
560         if (!stroke->isHairlineStyle()) {
561             stroke.writable()->setHairlineStyle();
562         }
563     }
564 
565     const bool isHairline = stroke->isHairlineStyle();
566 
567     // Save the current xp on the draw state so we can reset it if needed
568     const GrXPFactory* xpFactory = pipelineBuilder->getXPFactory();
569     SkAutoTUnref<const GrXPFactory> backupXPFactory(SkSafeRef(xpFactory));
570     // face culling doesn't make sense here
571     SkASSERT(GrPipelineBuilder::kBoth_DrawFace == pipelineBuilder->getDrawFace());
572 
573     int                         passCount = 0;
574     const GrStencilSettings*    passes[3];
575     GrPipelineBuilder::DrawFace drawFace[3];
576     bool                        reverse = false;
577     bool                        lastPassIsBounds;
578 
579     if (isHairline) {
580         passCount = 1;
581         if (stencilOnly) {
582             passes[0] = &gDirectToStencil;
583         } else {
584             passes[0] = nullptr;
585         }
586         lastPassIsBounds = false;
587         drawFace[0] = GrPipelineBuilder::kBoth_DrawFace;
588     } else {
589         if (single_pass_path(path, *stroke)) {
590             passCount = 1;
591             if (stencilOnly) {
592                 passes[0] = &gDirectToStencil;
593             } else {
594                 passes[0] = nullptr;
595             }
596             drawFace[0] = GrPipelineBuilder::kBoth_DrawFace;
597             lastPassIsBounds = false;
598         } else {
599             switch (path.getFillType()) {
600                 case SkPath::kInverseEvenOdd_FillType:
601                     reverse = true;
602                     // fallthrough
603                 case SkPath::kEvenOdd_FillType:
604                     passes[0] = &gEOStencilPass;
605                     if (stencilOnly) {
606                         passCount = 1;
607                         lastPassIsBounds = false;
608                     } else {
609                         passCount = 2;
610                         lastPassIsBounds = true;
611                         if (reverse) {
612                             passes[1] = &gInvEOColorPass;
613                         } else {
614                             passes[1] = &gEOColorPass;
615                         }
616                     }
617                     drawFace[0] = drawFace[1] = GrPipelineBuilder::kBoth_DrawFace;
618                     break;
619 
620                 case SkPath::kInverseWinding_FillType:
621                     reverse = true;
622                     // fallthrough
623                 case SkPath::kWinding_FillType:
624                     if (fSeparateStencil) {
625                         if (fStencilWrapOps) {
626                             passes[0] = &gWindStencilSeparateWithWrap;
627                         } else {
628                             passes[0] = &gWindStencilSeparateNoWrap;
629                         }
630                         passCount = 2;
631                         drawFace[0] = GrPipelineBuilder::kBoth_DrawFace;
632                     } else {
633                         if (fStencilWrapOps) {
634                             passes[0] = &gWindSingleStencilWithWrapInc;
635                             passes[1] = &gWindSingleStencilWithWrapDec;
636                         } else {
637                             passes[0] = &gWindSingleStencilNoWrapInc;
638                             passes[1] = &gWindSingleStencilNoWrapDec;
639                         }
640                         // which is cw and which is ccw is arbitrary.
641                         drawFace[0] = GrPipelineBuilder::kCW_DrawFace;
642                         drawFace[1] = GrPipelineBuilder::kCCW_DrawFace;
643                         passCount = 3;
644                     }
645                     if (stencilOnly) {
646                         lastPassIsBounds = false;
647                         --passCount;
648                     } else {
649                         lastPassIsBounds = true;
650                         drawFace[passCount-1] = GrPipelineBuilder::kBoth_DrawFace;
651                         if (reverse) {
652                             passes[passCount-1] = &gInvWindColorPass;
653                         } else {
654                             passes[passCount-1] = &gWindColorPass;
655                         }
656                     }
657                     break;
658                 default:
659                     SkDEBUGFAIL("Unknown path fFill!");
660                     return false;
661             }
662         }
663     }
664 
665     SkScalar tol = GrPathUtils::kDefaultTolerance;
666     SkScalar srcSpaceTol = GrPathUtils::scaleToleranceToSrc(tol, viewMatrix, path.getBounds());
667 
668     SkRect devBounds;
669     GetPathDevBounds(path, pipelineBuilder->getRenderTarget(), viewMatrix, &devBounds);
670 
671     for (int p = 0; p < passCount; ++p) {
672         pipelineBuilder->setDrawFace(drawFace[p]);
673         if (passes[p]) {
674             *pipelineBuilder->stencil() = *passes[p];
675         }
676 
677         if (lastPassIsBounds && (p == passCount-1)) {
678             // Reset the XP Factory on pipelineBuilder
679             pipelineBuilder->setXPFactory(backupXPFactory);
680             SkRect bounds;
681             SkMatrix localMatrix = SkMatrix::I();
682             if (reverse) {
683                 SkASSERT(pipelineBuilder->getRenderTarget());
684                 // draw over the dev bounds (which will be the whole dst surface for inv fill).
685                 bounds = devBounds;
686                 SkMatrix vmi;
687                 // mapRect through persp matrix may not be correct
688                 if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) {
689                     vmi.mapRect(&bounds);
690                 } else {
691                     if (!viewMatrix.invert(&localMatrix)) {
692                         return false;
693                     }
694                 }
695             } else {
696                 bounds = path.getBounds();
697             }
698             const SkMatrix& viewM = (reverse && viewMatrix.hasPerspective()) ? SkMatrix::I() :
699                                                                                viewMatrix;
700             SkAutoTUnref<GrDrawBatch> batch(
701                     GrRectBatchFactory::CreateNonAAFill(color, viewM, bounds, nullptr,
702                                                         &localMatrix));
703             target->drawBatch(*pipelineBuilder, batch);
704         } else {
705             if (passCount > 1) {
706                 pipelineBuilder->setDisableColorXPFactory();
707             }
708 
709             DefaultPathBatch::Geometry geometry;
710             geometry.fColor = color;
711             geometry.fPath = path;
712             geometry.fTolerance = srcSpaceTol;
713 
714             SkAutoTUnref<GrDrawBatch> batch(DefaultPathBatch::Create(geometry, newCoverage,
715                                                                      viewMatrix, isHairline,
716                                                                      devBounds));
717 
718             target->drawBatch(*pipelineBuilder, batch);
719         }
720     }
721     return true;
722 }
723 
onCanDrawPath(const CanDrawPathArgs & args) const724 bool GrDefaultPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
725     // this class can draw any path with any fill but doesn't do any anti-aliasing.
726     return !args.fAntiAlias && (args.fStroke->isFillStyle() ||
727                                 IsStrokeHairlineOrEquivalent(*args.fStroke, *args.fViewMatrix,
728                                                              nullptr));
729 }
730 
onDrawPath(const DrawPathArgs & args)731 bool GrDefaultPathRenderer::onDrawPath(const DrawPathArgs& args) {
732     GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(), "GrDefaultPathRenderer::onDrawPath");
733     return this->internalDrawPath(args.fTarget,
734                                   args.fPipelineBuilder,
735                                   args.fColor,
736                                   *args.fViewMatrix,
737                                   *args.fPath,
738                                   *args.fStroke,
739                                   false);
740 }
741 
onStencilPath(const StencilPathArgs & args)742 void GrDefaultPathRenderer::onStencilPath(const StencilPathArgs& args) {
743     GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(),"GrDefaultPathRenderer::onStencilPath");
744     SkASSERT(SkPath::kInverseEvenOdd_FillType != args.fPath->getFillType());
745     SkASSERT(SkPath::kInverseWinding_FillType != args.fPath->getFillType());
746     this->internalDrawPath(args.fTarget, args.fPipelineBuilder, GrColor_WHITE, *args.fViewMatrix,
747                            *args.fPath, *args.fStroke, true);
748 }
749 
750 ///////////////////////////////////////////////////////////////////////////////////////////////////
751 
752 #ifdef GR_TEST_UTILS
753 
DRAW_BATCH_TEST_DEFINE(DefaultPathBatch)754 DRAW_BATCH_TEST_DEFINE(DefaultPathBatch) {
755     GrColor color = GrRandomColor(random);
756     SkMatrix viewMatrix = GrTest::TestMatrix(random);
757 
758     // For now just hairlines because the other types of draws require two batches.
759     // TODO we should figure out a way to combine the stencil and cover steps into one batch
760     GrStrokeInfo stroke(SkStrokeRec::kHairline_InitStyle);
761     SkPath path = GrTest::TestPath(random);
762 
763     // Compute srcSpaceTol
764     SkRect bounds = path.getBounds();
765     SkScalar tol = GrPathUtils::kDefaultTolerance;
766     SkScalar srcSpaceTol = GrPathUtils::scaleToleranceToSrc(tol, viewMatrix, bounds);
767 
768     DefaultPathBatch::Geometry geometry;
769     geometry.fColor = color;
770     geometry.fPath = path;
771     geometry.fTolerance = srcSpaceTol;
772 
773     viewMatrix.mapRect(&bounds);
774     uint8_t coverage = GrRandomCoverage(random);
775     return DefaultPathBatch::Create(geometry, coverage, viewMatrix, true, bounds);
776 }
777 
778 #endif
779