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
26GrDefaultPathRenderer::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
38GR_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
47GR_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.
56GR_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
70GR_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.
82GR_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.
94GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilWithWrapInc,
95    kIncWrap_StencilOp,
96    kKeep_StencilOp,
97    kAlwaysIfInClip_StencilFunc,
98    0xffff,
99    0xffff,
100    0xffff);
101
102GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilWithWrapDec,
103    kDecWrap_StencilOp,
104    kKeep_StencilOp,
105    kAlwaysIfInClip_StencilFunc,
106    0xffff,
107    0xffff,
108    0xffff);
109
110GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilNoWrapInc,
111    kInvert_StencilOp,
112    kIncClamp_StencilOp,
113    kEqual_StencilFunc,
114    0xffff,
115    0xffff,
116    0xffff);
117
118GR_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
128GR_STATIC_CONST_SAME_STENCIL(gWindColorPass,
129    kZero_StencilOp,
130    kZero_StencilOp,
131    kNonZeroIfInClip_StencilFunc,
132    0xffff,
133    0x0000,
134    0xffff);
135
136GR_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.
148GR_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
161static 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
172GrPathRenderer::StencilSupport
173GrDefaultPathRenderer::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
181static 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
195static 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
213class DefaultPathBatch : public GrVertexBatch {
214public:
215    DEFINE_BATCH_CLASS_ID
216
217    struct Geometry {
218        GrColor fColor;
219        SkPath fPath;
220        SkScalar fTolerance;
221    };
222
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
229    const char* name() const override { return "DefaultPathBatch"; }
230
231    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
239private:
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
254    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
379    SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
380
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
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
426    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
523    GrColor color() const { return fBatch.fColor; }
524    uint8_t coverage() const { return fBatch.fCoverage; }
525    bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
526    const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; }
527    bool isHairline() const { return fBatch.fIsHairline; }
528    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
546bool 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
724bool 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
731bool 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
742void 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
754DRAW_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